Document asSubscriber stage (#28128)
* Unfortunately it seems the jdk9-only tests could not actually be compiled. With these changes those can actually be compiled and ran again. * Always link to jdk11 for java.* javadocs * Update sbt-paradox-akka to fix linking to inner classes for javadoc
This commit is contained in:
parent
619a4494d5
commit
25ad10f893
9 changed files with 195 additions and 13 deletions
|
|
@ -4,12 +4,51 @@ Integration with Reactive Streams, materializes into a `org.reactivestreams.Subs
|
||||||
|
|
||||||
@ref[Source operators](../index.md#source-operators)
|
@ref[Source operators](../index.md#source-operators)
|
||||||
|
|
||||||
@@@ div { .group-scala }
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
@@signature [Source.scala](/akka-stream/src/main/scala/akka/stream/scaladsl/Source.scala) { #asSubscriber }
|
@@@ div { .group-scala }
|
||||||
|
|
||||||
|
@@snip[JavaFlowSupport.scala](/akka-stream/src/main/scala-jdk-9/akka/stream/scaladsl/JavaFlowSupport.scala) { #asSubscriber }
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
@@@ div { .group-java }
|
||||||
|
|
||||||
|
@@snip[JavaFlowSupport.java](/akka-stream/src/main/java-jdk-9/akka/stream/javadsl/JavaFlowSupport.java) { #asSubscriber }
|
||||||
|
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
TODO: We would welcome help on contributing descriptions and examples, see: https://github.com/akka/akka/issues/25646
|
If you want to create a @apidoc[Source] that gets its elements from another library that supports
|
||||||
|
[Reactive Streams](https://www.reactive-streams.org/), you can use `JavaFlowSupport.Source.asSubscriber`.
|
||||||
|
Each time this @apidoc[Source] is materialized, it produces a materialized value of type
|
||||||
|
@javadoc[java.util.concurrent.Flow.Subscriber](java.util.concurrent.Flow.Subscriber).
|
||||||
|
This @javadoc[Subscriber](java.util.concurrent.Flow.Subscriber) can be attached to a
|
||||||
|
[Reactive Streams](https://www.reactive-streams.org/) @javadoc[Publisher](java.util.concurrent.Flow.Publisher)
|
||||||
|
to populate it.
|
||||||
|
|
||||||
|
@@@ note
|
||||||
|
|
||||||
|
For JDK 8 users: since @javadoc[java.util.concurrent.Flow](java.util.concurrent.Flow) was introduced in JDK version 9,
|
||||||
|
if you are still on version 8 you may use the [org.reactivestreams](https://github.com/reactive-streams/reactive-streams-jvm#reactive-streams) library with `Source.asSubscriber` and `Flow.asSubscriber`.
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Suppose we use a database client that supports [Reactive Streams](https://www.reactive-streams.org/),
|
||||||
|
we could create a @apidoc[Source] that queries the database for its rows. That @apidoc[Source] can then
|
||||||
|
be used for further processing, for example creating a @apidoc[Source] that contains the names of the
|
||||||
|
rows.
|
||||||
|
|
||||||
|
Note that since the database is queried for each materialization, the `rowSource` can be safely re-used.
|
||||||
|
Because both the database driver and Akka Streams support [Reactive Streams](https://www.reactive-streams.org/),
|
||||||
|
backpressure is applied throughout the stream, preventing us from running out of memory when the database
|
||||||
|
rows are consumed slower than they are produced by the database.
|
||||||
|
|
||||||
|
Scala
|
||||||
|
: @@snip [AsSubscriber.scala](/akka-docs/src/test/scala-jdk9-only/docs/stream/operators/source/AsSubscriber.scala) { #imports #example }
|
||||||
|
|
||||||
|
Java
|
||||||
|
: @@snip [AsSubscriber.java](/akka-docs/src/test/java-jdk9-only/jdocs/stream/operators/source/AsSubscriber.java) { #imports #example }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Lightbend Inc. <https://www.lightbend.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdocs.stream.operators.source;
|
||||||
|
|
||||||
|
//#imports
|
||||||
|
import java.util.concurrent.Flow.Subscriber;
|
||||||
|
import java.util.concurrent.Flow.Publisher;
|
||||||
|
|
||||||
|
import akka.NotUsed;
|
||||||
|
import akka.stream.javadsl.Source;
|
||||||
|
import akka.stream.javadsl.JavaFlowSupport;
|
||||||
|
|
||||||
|
//#imports
|
||||||
|
|
||||||
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
|
|
||||||
|
public interface AsSubscriber {
|
||||||
|
static class JavaFlowSupport {
|
||||||
|
public static final class Source {
|
||||||
|
public
|
||||||
|
// #api
|
||||||
|
static <T> akka.stream.javadsl.Source<T, Subscriber<T>> asSubscriber()
|
||||||
|
// #api
|
||||||
|
{
|
||||||
|
return akka.stream.javadsl.JavaFlowSupport.Source.<T>asSubscriber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Row {
|
||||||
|
public String getField(String fieldName) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DatabaseClient {
|
||||||
|
Publisher<Row> fetchRows() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseClient databaseClient = null;
|
||||||
|
|
||||||
|
// #example
|
||||||
|
class Example {
|
||||||
|
Source<Row, NotUsed> rowSource =
|
||||||
|
JavaFlowSupport.Source.<Row>asSubscriber()
|
||||||
|
.mapMaterializedValue(
|
||||||
|
subscriber -> {
|
||||||
|
// For each materialization, fetch the rows from the database:
|
||||||
|
Publisher<Row> rows = databaseClient.fetchRows();
|
||||||
|
rows.subscribe(subscriber);
|
||||||
|
|
||||||
|
return NotUsed.getInstance();
|
||||||
|
});
|
||||||
|
|
||||||
|
public Source<String, NotUsed> names() {
|
||||||
|
// rowSource can be re-used, since it will start a new
|
||||||
|
// query for each materialization, fully supporting backpressure
|
||||||
|
// for each materialized stream:
|
||||||
|
return rowSource.map(row -> row.getField("name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #example
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Lightbend Inc. <https://www.lightbend.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package docs.stream.operators.source;
|
||||||
|
|
||||||
|
//#imports
|
||||||
|
import java.util.concurrent.Flow.Subscriber;
|
||||||
|
import java.util.concurrent.Flow.Publisher;
|
||||||
|
|
||||||
|
import akka.NotUsed;
|
||||||
|
import akka.stream.scaladsl.Source;
|
||||||
|
import akka.stream.scaladsl.JavaFlowSupport;
|
||||||
|
|
||||||
|
//#imports
|
||||||
|
|
||||||
|
object AsSubscriber {
|
||||||
|
case class Row(name: String)
|
||||||
|
|
||||||
|
class DatabaseClient {
|
||||||
|
def fetchRows(): Publisher[Row] = ???
|
||||||
|
}
|
||||||
|
|
||||||
|
val databaseClient: DatabaseClient = ???;
|
||||||
|
|
||||||
|
// #example
|
||||||
|
val rowSource: Source[Row, NotUsed] =
|
||||||
|
JavaFlowSupport.Source.asSubscriber
|
||||||
|
.mapMaterializedValue(
|
||||||
|
(subscriber: Subscriber[Row]) => {
|
||||||
|
// For each materialization, fetch the rows from the database:
|
||||||
|
val rows: Publisher[Row] = databaseClient.fetchRows()
|
||||||
|
rows.subscribe(subscriber)
|
||||||
|
NotUsed
|
||||||
|
});
|
||||||
|
|
||||||
|
val names: Source[String, NotUsed] =
|
||||||
|
// rowSource can be re-used, since it will start a new
|
||||||
|
// query for each materialization, fully supporting backpressure
|
||||||
|
// for each materialized stream:
|
||||||
|
rowSource.map(row => row.name);
|
||||||
|
//#example
|
||||||
|
}
|
||||||
|
|
@ -52,7 +52,9 @@ public final class JavaFlowSupport {
|
||||||
* See also {@code Source.asSubscriber} if wanting to integrate with {@link org.reactivestreams.Subscriber} instead
|
* See also {@code Source.asSubscriber} if wanting to integrate with {@link org.reactivestreams.Subscriber} instead
|
||||||
* (which carries the same semantics, however existed before RS's inclusion in Java 9).
|
* (which carries the same semantics, however existed before RS's inclusion in Java 9).
|
||||||
*/
|
*/
|
||||||
|
//#asSubscriber
|
||||||
public static <T> akka.stream.javadsl.Source<T, java.util.concurrent.Flow.Subscriber<T>> asSubscriber() {
|
public static <T> akka.stream.javadsl.Source<T, java.util.concurrent.Flow.Subscriber<T>> asSubscriber() {
|
||||||
|
//#asSubscriber
|
||||||
return akka.stream.javadsl.Source.<T>asSubscriber().mapMaterializedValue(JavaFlowAndRsConverters::asJava);
|
return akka.stream.javadsl.Source.<T>asSubscriber().mapMaterializedValue(JavaFlowAndRsConverters::asJava);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,9 @@ object JavaFlowSupport {
|
||||||
* @see See also [[Source.asSubscriber]] if wanting to integrate with [[org.reactivestreams.Subscriber]] instead
|
* @see See also [[Source.asSubscriber]] if wanting to integrate with [[org.reactivestreams.Subscriber]] instead
|
||||||
* (which carries the same semantics, however existed before RS's inclusion in Java 9).
|
* (which carries the same semantics, however existed before RS's inclusion in Java 9).
|
||||||
*/
|
*/
|
||||||
final def asSubscriber[T]: Source[T, juc.Flow.Subscriber[T]] =
|
//#asSubscriber
|
||||||
|
final def asSubscriber[T]: Source[T, java.util.concurrent.Flow.Subscriber[T]] =
|
||||||
|
//#asSubscriber
|
||||||
scaladsl.Source.asSubscriber[T].mapMaterializedValue(_.asJava)
|
scaladsl.Source.asSubscriber[T].mapMaterializedValue(_.asJava)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
17
build.sbt
17
build.sbt
|
|
@ -102,7 +102,8 @@ lazy val akkaScalaNightly = akkaModule("akka-scala-nightly")
|
||||||
.disablePlugins(ValidatePullRequest, MimaPlugin, CopyrightHeaderInPr)
|
.disablePlugins(ValidatePullRequest, MimaPlugin, CopyrightHeaderInPr)
|
||||||
|
|
||||||
lazy val benchJmh = akkaModule("akka-bench-jmh")
|
lazy val benchJmh = akkaModule("akka-bench-jmh")
|
||||||
.dependsOn(Seq(actor, actorTyped, stream, streamTests, persistence, distributedData, jackson, testkit).map(
|
.enablePlugins(Jdk9)
|
||||||
|
.dependsOn(Seq(actor, actorTyped, stream, streamTestkit, persistence, distributedData, jackson, testkit).map(
|
||||||
_ % "compile->compile;compile->test"): _*)
|
_ % "compile->compile;compile->test"): _*)
|
||||||
.settings(Dependencies.benchJmh)
|
.settings(Dependencies.benchJmh)
|
||||||
.settings(javacOptions += "-parameters") // for Jackson
|
.settings(javacOptions += "-parameters") // for Jackson
|
||||||
|
|
@ -170,6 +171,7 @@ lazy val distributedData = akkaModule("akka-distributed-data")
|
||||||
.enablePlugins(MultiNodeScalaTest)
|
.enablePlugins(MultiNodeScalaTest)
|
||||||
|
|
||||||
lazy val docs = akkaModule("akka-docs")
|
lazy val docs = akkaModule("akka-docs")
|
||||||
|
.configs(akka.Jdk9.TestJdk9)
|
||||||
.dependsOn(
|
.dependsOn(
|
||||||
actor,
|
actor,
|
||||||
cluster,
|
cluster,
|
||||||
|
|
@ -180,6 +182,7 @@ lazy val docs = akkaModule("akka-docs")
|
||||||
persistenceQuery,
|
persistenceQuery,
|
||||||
distributedData,
|
distributedData,
|
||||||
stream,
|
stream,
|
||||||
|
stream % "TestJdk9->CompileJdk9",
|
||||||
actorTyped,
|
actorTyped,
|
||||||
clusterTools % "compile->compile;test->test",
|
clusterTools % "compile->compile;test->test",
|
||||||
clusterSharding % "compile->compile;test->test",
|
clusterSharding % "compile->compile;test->test",
|
||||||
|
|
@ -201,7 +204,8 @@ lazy val docs = akkaModule("akka-docs")
|
||||||
NoPublish,
|
NoPublish,
|
||||||
ParadoxBrowse,
|
ParadoxBrowse,
|
||||||
ScaladocNoVerificationOfDiagrams,
|
ScaladocNoVerificationOfDiagrams,
|
||||||
StreamOperatorsIndexGenerator)
|
StreamOperatorsIndexGenerator,
|
||||||
|
Jdk9)
|
||||||
.disablePlugins(MimaPlugin, WhiteSourcePlugin)
|
.disablePlugins(MimaPlugin, WhiteSourcePlugin)
|
||||||
.disablePlugins(ScalafixPlugin)
|
.disablePlugins(ScalafixPlugin)
|
||||||
|
|
||||||
|
|
@ -344,9 +348,14 @@ lazy val streamTestkit = akkaModule("akka-stream-testkit")
|
||||||
.disablePlugins(MimaPlugin)
|
.disablePlugins(MimaPlugin)
|
||||||
|
|
||||||
lazy val streamTests = akkaModule("akka-stream-tests")
|
lazy val streamTests = akkaModule("akka-stream-tests")
|
||||||
.dependsOn(streamTestkit % "test->test", remote % "test->test", stream)
|
.configs(akka.Jdk9.TestJdk9)
|
||||||
|
.dependsOn(
|
||||||
|
streamTestkit % "test->test",
|
||||||
|
remote % "test->test",
|
||||||
|
stream % "TestJdk9->CompileJdk9"
|
||||||
|
)
|
||||||
.settings(Dependencies.streamTests)
|
.settings(Dependencies.streamTests)
|
||||||
.enablePlugins(NoPublish)
|
.enablePlugins(NoPublish, Jdk9)
|
||||||
.disablePlugins(MimaPlugin, WhiteSourcePlugin)
|
.disablePlugins(MimaPlugin, WhiteSourcePlugin)
|
||||||
|
|
||||||
lazy val streamTestsTck = akkaModule("akka-stream-tests-tck")
|
lazy val streamTestsTck = akkaModule("akka-stream-tests-tck")
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ import sbt.Keys._
|
||||||
object Jdk9 extends AutoPlugin {
|
object Jdk9 extends AutoPlugin {
|
||||||
import JdkOptions.notOnJdk8
|
import JdkOptions.notOnJdk8
|
||||||
|
|
||||||
lazy val CompileJdk9 = config("CompileJdk9").extend(Compile)
|
val CompileJdk9 = config("CompileJdk9").extend(Compile)
|
||||||
|
|
||||||
|
val TestJdk9 = config("TestJdk9").extend(Test)
|
||||||
|
|
||||||
val SCALA_SOURCE_DIRECTORY = "scala-jdk-9"
|
val SCALA_SOURCE_DIRECTORY = "scala-jdk-9"
|
||||||
val SCALA_TEST_SOURCE_DIRECTORY = "scala-jdk9-only"
|
val SCALA_TEST_SOURCE_DIRECTORY = "scala-jdk9-only"
|
||||||
|
|
@ -20,12 +22,26 @@ object Jdk9 extends AutoPlugin {
|
||||||
val compileJdk9Settings = Seq(
|
val compileJdk9Settings = Seq(
|
||||||
// following the scala-2.12, scala-sbt-1.0, ... convention
|
// following the scala-2.12, scala-sbt-1.0, ... convention
|
||||||
unmanagedSourceDirectories := notOnJdk8(
|
unmanagedSourceDirectories := notOnJdk8(
|
||||||
Seq(
|
Seq(
|
||||||
(Compile / sourceDirectory).value / SCALA_SOURCE_DIRECTORY,
|
(Compile / sourceDirectory).value / SCALA_SOURCE_DIRECTORY,
|
||||||
(Compile / sourceDirectory).value / JAVA_SOURCE_DIRECTORY)),
|
(Compile / sourceDirectory).value / JAVA_SOURCE_DIRECTORY)),
|
||||||
|
|
||||||
scalacOptions := AkkaBuild.DefaultScalacOptions ++ notOnJdk8(Seq("-release", "11")),
|
scalacOptions := AkkaBuild.DefaultScalacOptions ++ notOnJdk8(Seq("-release", "11")),
|
||||||
javacOptions := AkkaBuild.DefaultJavacOptions ++ notOnJdk8(Seq("--release", "11")))
|
javacOptions := AkkaBuild.DefaultJavacOptions ++ notOnJdk8(Seq("--release", "11")))
|
||||||
|
|
||||||
|
val testJdk9Settings = Seq(
|
||||||
|
// following the scala-2.12, scala-sbt-1.0, ... convention
|
||||||
|
unmanagedSourceDirectories := notOnJdk8(
|
||||||
|
Seq(
|
||||||
|
(Test / sourceDirectory).value / SCALA_TEST_SOURCE_DIRECTORY,
|
||||||
|
(Test / sourceDirectory).value / JAVA_TEST_SOURCE_DIRECTORY)),
|
||||||
|
|
||||||
|
scalacOptions := AkkaBuild.DefaultScalacOptions ++ notOnJdk8(Seq("-release", "11")),
|
||||||
|
javacOptions := AkkaBuild.DefaultJavacOptions ++ notOnJdk8(Seq("--release", "11")),
|
||||||
|
classpathConfiguration := TestJdk9,
|
||||||
|
externalDependencyClasspath := (externalDependencyClasspath in Test).value
|
||||||
|
)
|
||||||
|
|
||||||
val compileSettings = Seq(
|
val compileSettings = Seq(
|
||||||
// It might have been more 'neat' to add the jdk9 products to the jar via packageBin/mappings, but that doesn't work with the OSGi plugin,
|
// It might have been more 'neat' to add the jdk9 products to the jar via packageBin/mappings, but that doesn't work with the OSGi plugin,
|
||||||
// so we add them to the fullClasspath instead.
|
// so we add them to the fullClasspath instead.
|
||||||
|
|
@ -38,5 +54,7 @@ object Jdk9 extends AutoPlugin {
|
||||||
override lazy val projectSettings =
|
override lazy val projectSettings =
|
||||||
inConfig(CompileJdk9)(Defaults.compileSettings) ++
|
inConfig(CompileJdk9)(Defaults.compileSettings) ++
|
||||||
inConfig(CompileJdk9)(compileJdk9Settings) ++
|
inConfig(CompileJdk9)(compileJdk9Settings) ++
|
||||||
compileSettings
|
compileSettings ++
|
||||||
|
inConfig(TestJdk9)(Defaults.testSettings) ++
|
||||||
|
inConfig(TestJdk9)(testJdk9Settings)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ object Paradox {
|
||||||
"extref.ecs.base_url" -> "https://example.lightbend.com/v1/download/%s",
|
"extref.ecs.base_url" -> "https://example.lightbend.com/v1/download/%s",
|
||||||
"scaladoc.akka.base_url" -> "https://doc.akka.io/api/akka/2.6",
|
"scaladoc.akka.base_url" -> "https://doc.akka.io/api/akka/2.6",
|
||||||
"scaladoc.akka.http.base_url" -> "https://doc.akka.io/api/akka-http/current",
|
"scaladoc.akka.http.base_url" -> "https://doc.akka.io/api/akka-http/current",
|
||||||
|
"javadoc.java.base_url" -> "https://docs.oracle.com/en/java/javase/11/docs/api/java.base/",
|
||||||
|
"javadoc.java.link_style" -> "direct",
|
||||||
"javadoc.akka.base_url" -> "https://doc.akka.io/japi/akka/2.6",
|
"javadoc.akka.base_url" -> "https://doc.akka.io/japi/akka/2.6",
|
||||||
"javadoc.akka.link_style" -> "direct",
|
"javadoc.akka.link_style" -> "direct",
|
||||||
"javadoc.akka.http.base_url" -> "https://doc.akka.io/japi/akka-http/current",
|
"javadoc.akka.http.base_url" -> "https://doc.akka.io/japi/akka-http/current",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue