Java API checklist (#25762)

This commit is contained in:
Johan Andrén 2018-10-12 13:06:42 +02:00 committed by GitHub
parent 1e883ced45
commit d9a41f5e23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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<T>` (`OptionalDouble`, ...) |
| `scala.collection.immutable.Seq[T]` | `java.util.List<T>` |
| `scala.concurrent.Future[T]` | `java.util.concurrent.CompletionStage<T>` |
| `scala.concurrent.Promise[T]` | `java.util.concurrent.CompletableFuture<T>` |
| `scala.concurrent.duration.FiniteDuration` | `java.time.Duration` (use `akka.util.JavaDurationConverters`) |
| `T => Unit` | `java.util.function.Consumer<T>` |
| `() => R` (`scala.Function0[R]`) | `java.util.function.Supplier<R>` |
| `T => R` (`scala.Function1[T, R]`) | `java.util.function.Function<T, R>` |
## Contributing new Akka Streams operators
Documentation of Akka Streams operators is automatically enforced.