From d9a41f5e237a841b7f15e198fb5c22673b6ed1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Andr=C3=A9n?= Date: Fri, 12 Oct 2018 13:06:42 +0200 Subject: [PATCH] Java API checklist (#25762) --- CONTRIBUTING.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2158cc0c93..b6691cc63b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -383,6 +383,74 @@ tested it becomes an officially supported Akka feature. [List of Akka features marked as may change](http://doc.akka.io/docs/akka/current/common/may-change.html) +## Java APIs in Akka + +Akka, aims to keep 100% feature parity between the Java and Scala. Implementing even the API for Java in +Scala has proven the most viable way to do it, as long as you keep the following in mind: + +1. Keep entry points separated in `javadsl` and `scaladsl` unless changing existing APIs which for historical + and binary compatibility reasons do not have this subdivision. + +1. Have methods in the `javadsl` package delegate to the methods in the Scala API, or the common internal implementation. + The Akka Stream Scala instances for example have a `.asJava` method to convert to the `akka.stream.javadsl` counterparts. + +1. When using Scala `object` instances, offer a `getInstance()` method and add a sealed abstract class + (to support Scala 2.11) to get the return type. See `akka.Done` for an example. + +1. When the Scala API contains an `apply` method, use `create` or `of` for Java users. + +1. Do not nest Scala `object`s more than two levels. + +1. Do not define traits nested in other classes or in objects deeper than one level. + +1. Be careful to convert values within data structures (eg. for `scala.Long` vs. `java.lang.Long`, use `scala.Long.box(value)`) + +1. When compiling with both Scala 2.11 and 2.12, some methods considered overloads in 2.11, become ambiguous in + 2.12 as both may be functional interfaces. + +1. Complement any methods with Scala collections with a Java collection version + +1. Use the `akka.japi.Pair` class to return tuples + +1. If the underlying Scala code requires an `ExecutionContext`, make the Java API take an `Executor` and use + `ExecutionContext.fromExecutor(executor)` for conversion. + +1. Make use of `scala-java8-compat` conversions, see [GitHub](https://github.com/scala/scala-java8-compat) + (eg. `scala.compat.java8.FutureConverters` to translate Futures to `CompletionStage`s). + Note that we cannot upgrade to a newer version scala-java8-compat because of binary compatibility issues. + +1. Make sure there are Java tests or sample code touching all parts of the API + +1. Do not use lower type bounds: `trait[T] { def method[U >: Something]: U }` as they do not work with Java + +1. Provide `getX` style accessors for values in the Java APIs + +1. Place classes not part of the public APIs in a shared `internal` package. This package can contain implementations of + both Java and Scala APIs. Make such classes `private[akka]` and also, since that becomes `public` from Java's point of + view, annotate with `@InternalApi` and add a scaladoc saying `INTERNAL API` + +1. Companion objects (in Scala 2.11) cannot be accessed from Java if their companion is a trait, use an `abstract class` instead + +1. Traits that are part of the Java API should only be used to define pure interfaces, as soon as there are implementations of methods, prefer + `abstract class`. + + + +### Overview of Scala types and their Java counterparts + +| Scala | Java | +|-------|------| +| `scala.Option[T]` | `java.util.Optional` (`OptionalDouble`, ...) | +| `scala.collection.immutable.Seq[T]` | `java.util.List` | +| `scala.concurrent.Future[T]` | `java.util.concurrent.CompletionStage` | +| `scala.concurrent.Promise[T]` | `java.util.concurrent.CompletableFuture` | +| `scala.concurrent.duration.FiniteDuration` | `java.time.Duration` (use `akka.util.JavaDurationConverters`) | +| `T => Unit` | `java.util.function.Consumer` | +| `() => R` (`scala.Function0[R]`) | `java.util.function.Supplier` | +| `T => R` (`scala.Function1[T, R]`) | `java.util.function.Function` | + + + ## Contributing new Akka Streams operators Documentation of Akka Streams operators is automatically enforced.