diff --git a/.travis.yml b/.travis.yml index aa3ffa3..c926215 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,8 @@ env: script: - admin/build.sh scala: - - 2.11.6 + - 2.11.7 + - 2.12.0-M2 jdk: - oraclejdk8 notifications: diff --git a/build.sbt b/build.sbt index fa1d549..d959560 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,8 @@ def jwrite(dir: java.io.File)(name: String, content: String) = { } lazy val commonSettings = Seq( - scalaVersion := "2.11.6", + scalaVersion := "2.11.7", + crossScalaVersions := List("2.11.7", "2.12.0-M2"), organization := "org.scala-lang.modules", version := "0.6.0-SNAPSHOT", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, @@ -100,8 +101,8 @@ lazy val root = (project in file(".")). }, javacOptions in JavaDoc := Seq(), artifactName in packageDoc in JavaDoc := ((sv, mod, art) => "" + mod.name + "_" + sv.binary + "-" + mod.revision + "-javadoc.jar"), - libraryDependencies += compilerPlugin("com.typesafe.genjavadoc" % "genjavadoc-plugin" % "0.8" cross CrossVersion.full), - scalacOptions in Compile <+= target map (t => "-P:genjavadoc:out=" + (t / "java")) + libraryDependencies += compilerPlugin("com.typesafe.genjavadoc" % "genjavadoc-plugin" % "0.9" cross CrossVersion.full), + scalacOptions in Compile += "-P:genjavadoc:out=" + (target.value / "java") ))): _* ). settings( diff --git a/src/main/scala/scala/compat/java8/FutureConverters.scala b/src/main/scala/scala/compat/java8/FutureConverters.scala index 86fdddf..a2c0977 100644 --- a/src/main/scala/scala/compat/java8/FutureConverters.scala +++ b/src/main/scala/scala/compat/java8/FutureConverters.scala @@ -71,8 +71,14 @@ object FutureConverters { * @return a Scala Future that represents the CompletionStage's completion */ def toScala[T](cs: CompletionStage[T]): Future[T] = { - val p = new P[T] - cs whenComplete p + val p = Promise[T]() + val bc = new BiConsumer[T, Throwable] { + override def accept(v: T, e: Throwable): Unit = { + if (e == null) p.complete(Success(v)) + else p.complete(Failure(e)) + } + } + cs whenComplete bc p.future } diff --git a/src/main/scala/scala/concurrent/java8/FutureConvertersImpl.scala b/src/main/scala/scala/concurrent/java8/FutureConvertersImpl.scala index 14a917f..5c907e7 100644 --- a/src/main/scala/scala/concurrent/java8/FutureConvertersImpl.scala +++ b/src/main/scala/scala/concurrent/java8/FutureConvertersImpl.scala @@ -71,11 +71,4 @@ object FuturesConvertersImpl { override def toString: String = super[CompletableFuture].toString } - - class P[T] extends impl.Promise.DefaultPromise[T] with BiConsumer[T, Throwable] { - override def accept(v: T, e: Throwable): Unit = { - if (e == null) complete(Success(v)) - else complete(Failure(e)) - } - } } diff --git a/src/test/java/scala/compat/java8/FutureConvertersTest.java b/src/test/java/scala/compat/java8/FutureConvertersTest.java index d7fc1f2..a8d4861 100644 --- a/src/test/java/scala/compat/java8/FutureConvertersTest.java +++ b/src/test/java/scala/compat/java8/FutureConvertersTest.java @@ -3,321 +3,319 @@ */ package scala.compat.java8; +import org.junit.Test; +import scala.concurrent.Future; +import scala.concurrent.Promise; + import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; -import static java.util.concurrent.TimeUnit.*; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.*; - -import org.junit.Test; - -import scala.concurrent.Future; -import scala.concurrent.Promise; import static scala.compat.java8.FutureConverters.*; public class FutureConvertersTest { - @Test - public void testToScalaSuccess() { - final CompletableFuture cs = new CompletableFuture<>(); - final Future f = toScala(cs); - assertFalse("f must not yet be completed", f.isCompleted()); - cs.complete("Hello"); - assertTrue("f must be completed by now", f.isCompleted()); - assertEquals("Hello", f.value().get().get()); - } - - @Test - public void testToScalaFailure() { - final CompletableFuture cs = new CompletableFuture<>(); - final Future f = toScala(cs); - assertFalse("f must not yet be completed", f.isCompleted()); - final Exception ex = new RuntimeException("Hello"); - cs.completeExceptionally(ex); - assertTrue("f must be completed by now", f.isCompleted()); - assertEquals(ex, f.value().get().failed().get()); - } + @Test + public void testToScalaSuccess() { + final CompletableFuture cs = new CompletableFuture<>(); + final Future f = toScala(cs); + assertFalse("f must not yet be completed", f.isCompleted()); + cs.complete("Hello"); + assertTrue("f must be completed by now", f.isCompleted()); + assertEquals("Hello", f.value().get().get()); + } - @Test - public void testToJavaSuccess() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletableFuture cp = (CompletableFuture) cs; - assertFalse("cs must not yet be completed", cp.isDone()); - p.success("Hello"); - assertTrue("cs must be completed by now", cp.isDone()); - assertEquals("Hello", cp.get()); - } + @Test + public void testToScalaFailure() { + final CompletableFuture cs = new CompletableFuture<>(); + final Future f = toScala(cs); + assertFalse("f must not yet be completed", f.isCompleted()); + final Exception ex = new RuntimeException("Hello"); + cs.completeExceptionally(ex); + assertTrue("f must be completed by now", f.isCompleted()); + assertEquals(ex, f.value().get().failed().get()); + } - @Test - public void testToJavaFailure() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletableFuture cp = (CompletableFuture) cs; - assertFalse("cs must not yet be completed", cp.isDone()); - final Exception ex = new RuntimeException("Hello"); - p.failure(ex); - assertTrue("cs must be completed by now", cp.isDone()); - assertEquals("exceptionally equals", ex.toString(), cp.exceptionally(x -> x.toString()).get()); - Throwable thr = null; - try { - cp.get(); - } catch (Throwable t) { - thr = t; + @Test + public void testToJavaSuccess() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletableFuture cp = (CompletableFuture) cs; + assertFalse("cs must not yet be completed", cp.isDone()); + p.success("Hello"); + assertTrue("cs must be completed by now", cp.isDone()); + assertEquals("Hello", cp.get()); } - assertNotNull("get() must throw", thr); - assertEquals("thrown exception must be wrapped", ExecutionException.class, thr.getClass()); - assertEquals("wrapper must contain the right exception", ex, thr.getCause()); - } - @Test - public void testToJavaThenApply() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenApply(x -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - return x; - }); - p.success("Hello"); - latch.countDown(); - assertEquals("Hello", second.toCompletableFuture().get()); - } + @Test + public void testToJavaFailure() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletableFuture cp = (CompletableFuture) cs; + assertFalse("cs must not yet be completed", cp.isDone()); + final Exception ex = new RuntimeException("Hello"); + p.failure(ex); + assertTrue("cs must be completed by now", cp.isDone()); + assertEquals("exceptionally equals", ex.toString(), cp.exceptionally(x -> x.toString()).get()); + Throwable thr = null; + try { + cp.get(); + } catch (Throwable t) { + thr = t; + } + assertNotNull("get() must throw", thr); + assertEquals("thrown exception must be wrapped", ExecutionException.class, thr.getClass()); + assertEquals("wrapper must contain the right exception", ex, thr.getCause()); + } - @Test - public void testToJavaThenAccept() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenAccept(x -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenApply() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenApply(x -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + return x; + }); + p.success("Hello"); + latch.countDown(); + assertEquals("Hello", second.toCompletableFuture().get()); + } - @Test - public void testToJavaThenRun() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenRun(() -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenAccept() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenAccept(x -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaThenCombine() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = CompletableFuture.completedFuture(42); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenCombine(other, (x, y) -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - return x.length() + y; - }); - p.success("Hello"); - latch.countDown(); - assertEquals((Integer) 47, second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenRun() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenRun(() -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaThenAcceptBoth() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = CompletableFuture.completedFuture(42); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenAcceptBoth(other, (x, y) -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenCombine() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = CompletableFuture.completedFuture(42); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenCombine(other, (x, y) -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + return x.length() + y; + }); + p.success("Hello"); + latch.countDown(); + assertEquals((Integer) 47, second.toCompletableFuture().get()); + } - @Test - public void testToJavaRunAfterBoth() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = CompletableFuture.completedFuture(42); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.runAfterBoth(other, () -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenAcceptBoth() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = CompletableFuture.completedFuture(42); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenAcceptBoth(other, (x, y) -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaApplyToEither() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = new CompletableFuture<>(); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.applyToEither(other, x -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - return x.length(); - }); - p.success("Hello"); - latch.countDown(); - assertEquals((Integer) 5, second.toCompletableFuture().get()); - } + @Test + public void testToJavaRunAfterBoth() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = CompletableFuture.completedFuture(42); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.runAfterBoth(other, () -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaAcceptEither() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = new CompletableFuture<>(); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.acceptEither(other, x -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaApplyToEither() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = new CompletableFuture<>(); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.applyToEither(other, x -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + return x.length(); + }); + p.success("Hello"); + latch.countDown(); + assertEquals((Integer) 5, second.toCompletableFuture().get()); + } - @Test - public void testToJavaRunAfterEither() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CompletionStage other = new CompletableFuture<>(); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.runAfterEither(other, () -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - p.success("Hello"); - latch.countDown(); - assertNull("result must be Void", second.toCompletableFuture().get()); - } + @Test + public void testToJavaAcceptEither() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = new CompletableFuture<>(); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.acceptEither(other, x -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaThenCompose() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.thenCompose(x -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception e) { - throw new RuntimeException(e); - } - return CompletableFuture.completedFuture(x); - }); - p.success("Hello"); - latch.countDown(); - assertEquals("Hello", second.toCompletableFuture().get()); - } + @Test + public void testToJavaRunAfterEither() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CompletionStage other = new CompletableFuture<>(); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.runAfterEither(other, () -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + p.success("Hello"); + latch.countDown(); + assertNull("result must be Void", second.toCompletableFuture().get()); + } - @Test - public void testToJavaWhenComplete() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.whenComplete((v, e) -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - }); - p.success("Hello"); - latch.countDown(); - assertEquals("Hello", second.toCompletableFuture().get()); - } + @Test + public void testToJavaThenCompose() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.thenCompose(x -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + return CompletableFuture.completedFuture(x); + }); + p.success("Hello"); + latch.countDown(); + assertEquals("Hello", second.toCompletableFuture().get()); + } - @Test - public void testToJavaHandle() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.handle((v, e) -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - return v.length(); - }); - p.success("Hello"); - latch.countDown(); - assertEquals((Integer) 5, second.toCompletableFuture().get()); - } + @Test + public void testToJavaWhenComplete() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.whenComplete((v, e) -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + }); + p.success("Hello"); + latch.countDown(); + assertEquals("Hello", second.toCompletableFuture().get()); + } - @Test - public void testToJavaExceptionally() throws InterruptedException, - ExecutionException { - final Promise p = promise(); - final CompletionStage cs = toJava(p.future()); - final CountDownLatch latch = new CountDownLatch(1); - final CompletionStage second = cs.exceptionally(e -> { - try { - assertTrue("latch must succeed", latch.await(1, SECONDS)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - return e.getMessage(); - }); - p.failure(new RuntimeException("Hello")); - latch.countDown(); - assertEquals("Hello", second.toCompletableFuture().get()); - } + @Test + public void testToJavaHandle() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.handle((v, e) -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + return v.length(); + }); + p.success("Hello"); + latch.countDown(); + assertEquals((Integer) 5, second.toCompletableFuture().get()); + } + @Test + public void testToJavaExceptionally() throws InterruptedException, + ExecutionException { + final Promise p = promise(); + final CompletionStage cs = toJava(p.future()); + final CountDownLatch latch = new CountDownLatch(1); + final CompletionStage second = cs.exceptionally(e -> { + try { + assertTrue("latch must succeed", latch.await(1, SECONDS)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + return e.getMessage(); + }); + p.failure(new RuntimeException("Hello")); + latch.countDown(); + assertEquals("Hello", second.toCompletableFuture().get()); + } }