pjfanning opened a new issue, #2043:
URL: https://github.com/apache/pekko-connectors/issues/2043
A review of the `javadsl` packages across all connectors, plus the
settings/model classes reachable from them, found a number of places where the
Java API exposes Scala types or is otherwise hard to use from Java. This is a
tracking issue; items can be split into per-module PRs.
Notes:
- Findings came from reading the source (plus `javap` on existing compiled
classes where available). Items marked *(unverified)* are inferred from JLS
overload rules / erasure and should be confirmed with a small Java compile test
before fixing.
- Most fixes can be additive (new Java-friendly overloads/getters, deprecate
the old ones) to stay binary compatible; 2.0.0 also gives room to
remove/replace where that is cleaner.
## 1. Bugs (behavioural, not just API shape)
- [ ] **google-cloud-bigquery** `InsertAllRetryPolicy.scala:47` — `def
withoutDeduplication = WithDeduplication`; Java users silently get
deduplication.
- [ ] **google-fcm** `models/AndroidConfig.scala:192` —
`LightSettings.light_off_duration(value)` sets `light_on_duration`.
- [ ] **aws-event-bridge** `javadsl/EventBridgePublisher.scala:58` — 2-arg
`flowSeq(settings, client)` delegates to scaladsl `flow`, so it is identical to
`flow` and does not batch.
- [ ] **ironmq** `javadsl/IronMqProducer.scala:33,51,74` —
`asInstanceOf[Flow[_, String, _]]` over the value class `Message.Id`. Elements
are boxed `Message$Id` at runtime, so Java code reading them as `String` should
get a `ClassCastException` *(unverified; Java tests only check `.size()`)*. Use
`.map(_.value)`.
- [ ] **google-common** `GoogleSettings.scala:299` —
`ForwardProxy.create(connectionContext: HttpConnectionContext, ...)` casts to
`HttpsConnectionContext`; a plain HTTP context throws `ClassCastException`.
- [ ] **mqtt-streaming** `model.scala:1129` — `Command(..., completed:
Optional[CompletionStage[Done]], ...)` calls `toCompletableFuture.complete`,
which fails or completes a copy for non-`CompletableFuture` stages; failures
are never propagated.
- [ ] **testkit** `javadsl/LogCapturingExtension.scala:32`,
`LogCapturingJunit4.scala:37` — logback snippet names
`org.apache.pekko.actor.testkit.typed.internal.CapturingAppender` instead of
`org.apache.pekko.stream.connectors.testkit.CapturingAppender`.
## 2. High — Java cannot reasonably call it
### Ambiguous overloads (Java functional interface vs `scala.FunctionN` of
the same arity) *(unverified)*
Since Scala 2.12 `FunctionN` is SAM-compatible, so an implicitly typed Java
lambda matches both overloads.
- [ ] **cassandra** `CassandraSessionSettings.scala:42/50` — `withInit`
- [ ] **couchbase3** `javadsl/CouchbaseFlow.scala` — `insert` 156/177,
`replace` 202/223, `upsert` 248/269, `remove` 296/319, `exists` 378/390,
`touchDuration` 415/438, `touchInstant` 449/472 (deprecated `T => String`
variants; rename like `CouchbaseSink` did with `*Future`, or remove)
- [ ] **hbase** `HTableSettings.scala:43/49` — `withConverter`
- [ ] **jms / jakartams** `Destinations.scala:69-74` — `CustomDestination`
constructors (Java tests work around it with a typed helper); add
`CustomDestination.create(name, java.util.function.Function)`
- [ ] **mqttv5** `settings.scala:295/309` — `withAuth`; the Java variant
also uses `BiFunction[Int, MqttProperties, Pair[Int, MqttProperties]]`, which
erases to `Object`
### Scala types in javadsl signatures
- [ ] **unix-domain-socket** `javadsl/UnixDomainSocket.scala:190` —
`outgoingConnection(..., connectTimeout: scala.concurrent.duration.Duration)`;
add `java.time.Duration` overload
- [ ] **s3** `javadsl/S3.scala:744` —
`listObjectVersionsAndCommonPrefixes(..., prefix: Option[String], ...)`;
siblings use `Optional`
- [ ] **aws-event-bridge** `javadsl/EventBridgePublisher.scala:69` —
`flowSeq(client): Flow[scala Seq[PutEventsRequestEntry], ...]`
- [ ] **google-cloud-bigquery-storage** javadsl `BigQueryArrowStorage`,
`BigQueryAvroStorage`, `BigQueryStorage` — ~20 methods return `scala.Tuple2`
instead of `pekko.japi.Pair`
- [ ] **google-cloud-bigquery-storage**
`javadsl/BigQueryArrowStorage.scala:22`, `BigQueryAvroStorage.scala:21` — take
ScalaPB `TableReadOptions` (needs a Scala `Seq`), while
`javadsl/BigQueryStorage.scala` takes the Java protobuf type
- [ ] **dynamodb** `javadsl/DynamoDb.scala:56` — `flowWithContext` emits
`scala.util.Try` (`@ApiMayChange`)
### Varargs / static access
- [ ] **couchbase** `javadsl/CouchbaseSession.scala:280` — `createIndex(...,
fields: AnyRef*)` lacks `@varargs` (Java sees `immutable.Seq<Object>`); also
returns `CompletionStage[Boolean]` → `CompletionStage<Object>`
- [ ] **google-common** `javadsl/Google.scala:34` — `object Google extends
Google` with a trait companion, so no static forwarders; Java must use
`Google$.MODULE$`
- [ ] Top-level `case object`s needing `X$.MODULE$` from Java:
- **mqtt-streaming** `model.scala:123,125,479` — `PingReq`, `PingResp`,
`Disconnect`
- **google-fcm** `models/AndroidConfig.scala:146-178` — priority /
visibility values
- **solr** `SolrMessages.scala:131-136` — `Operation` values (low)
- **elasticsearch** `ElasticsearchWriteSettings.scala:25` — `RetryNever`
(low)
### Settings / models Java cannot build or read
- [ ] **sqs** `SqsSourceSettings.scala:113` —
`withVisibilityTimeout(FiniteDuration)` only
- [ ] **hdfs** `model.scala:209` — `RotationStrategy.time(FiniteDuration)`
only
- [ ] **s3** `S3Headers.scala:86` — `withCustomHeaders(scala Map)` only
- [ ] **s3** `settings.scala:789` — "Java API" `S3Settings.create(...,
allowedHeaders: Map[String, Set[String]])`; no `withAllowedHeaders` / Java
getter
- [ ] **s3** `model.scala:136` — `BucketVersioningResult.getStatus` returns
`scala.Option`
- [ ] **google-common** `GoogleSettings.scala:170` — `getForwardProxy`
returns `scala.Option`
- [ ] **google-cloud-storage** `StorageObject.scala:441` — "Java API"
`create` takes `Optional[Boolean]`, `Optional[scala Map]`, `Optional[Int]`,
`Optional[scala List]`
- [ ] **google-cloud-storage** `Owner.scala`, `ProjectTeam.scala`,
`CustomerEncryption.scala`, `ObjectAccessControls.scala` — constructor params
are not vals / no getters; contents unreadable
- [ ] **huawei-push-kit** `models/NotificationTarget.scala:21`
(`Tokens(Seq)`), `AndroidConfig.scala:98-123`, `WebConfig.scala:24-64` — Scala
`Seq`/`Map` only (repo Java example uses `new Set.Set1<>(...).toSeq()`)
- [ ] **google-fcm** `models/FcmNotification.scala:43`,
`AndroidConfig.scala:37,98,102,125`, `ApnsConfig.scala:24`,
`WebPushConfig.scala:24` — Scala `Seq`/`Map` only
- [ ] **solr** `SolrMessages.scala:122` — `WriteResult` (javadsl flow
output) exposes only `Option`/`Map`
- [ ] **google-cloud-bigquery-storage** `BigQueryRecordMapImpl.scala:20` —
`BigQueryRecord.get` returns `Option`
- [ ] **mqtt-streaming** `model.scala:1185` — `Event.carry: Option`;
`model.scala:307` — `Publish.packetId: Option[PacketId]` (`@InternalApi` value
class; Java test does `packetId().get().underlying()`)
## 3. Medium
### Scala primitives in generic positions (erase to `Object`)
- [ ] **couchbase** `javadsl/CouchbaseSession.scala:252,262` — `counter:
CompletionStage[Long]`
- [ ] **couchbase3** `javadsl/CouchbaseFlow.scala:367,378` — `exists:
Flow[T, Boolean, _]` (`CouchbaseSink.exists` uses `java.lang.Boolean`)
- [ ] **elasticsearch** `ReadResult.scala:32` — `getVersion: Optional[Long]`
- [ ] **google-cloud-bigquery** `model/QueryJsonProtocol.scala:66-67` —
`getMaximumBytesBilled: Optional[Long]`; `getLabels` returns `Optional[scala
Map]` (also `JobJsonProtocol.scala:88`)
- [ ] **s3** `model.scala:139,187` — `getMfaDelete` / `create(mfaDelete:
Optional[Boolean])`
- [ ] **google-cloud-storage** `StorageObject.scala:106-107` —
`getTemporaryHold` / `getEventBasedHold: Optional[Boolean]`
- [ ] **amqp** `AmqpConnectionProvider.scala:94,224,337` —
`java.util.List[Pair[String, Int]]`
- [ ] **unix-domain-socket** `javadsl/UnixDomainSocket.scala:50` —
`unbind(): CompletionStage[Unit]` → `BoxedUnit`
### Scala default args / implicit param lists in javadsl
- [ ] **couchbase3** `javadsl/CouchbaseSource.scala` — every method
(defaults + `implicit` collection/scope); give it the explicit overloads
`CouchbaseFlow`/`CouchbaseSink` already have
- [ ] **s3** `javadsl/S3.scala:68` `request`;
`:1102,1118,1438,1453,1504,1518` `completeMultipartUpload`, `deleteUpload`,
`putBucketVersioning` (`(implicit system, attributes = Attributes())`, no `(…,
system)` overload unlike siblings)
- [ ] **amqp** `javadsl/AmqpRpcFlow.scala:79` `committableFlow(...,
repliesPerMessage = 1)`
- [ ] **orientdb** `javadsl/OrientDbSource.scala:53` `typed(..., query =
null)`
- [ ] **mongodb** `javadsl/MongoFlow.scala:161` `replaceOne(collection,
options = ...)` with no 1-arg overload
- [ ] Redundant defaults: hdfs `HdfsSource.scala:81`, ftp
`FtpApi.scala:182,314,407,501`, mongodb `MongoFlow.scala:111`, s3 `S3.scala:628`
### Element/model getters with no Java alternative (on types Java users
receive)
- [ ] **google-cloud-pub-sub** `model.scala:96` —
`PubSubMessage.data/attributes/orderingKey`
- [ ] **influxdb** `InfluxDbWriteMessage.scala:86` —
`InfluxDbWriteResult.error`
- [ ] **kinesis** `CommittableRecord.scala:39` — `shutdownReason`
- [ ] **elasticsearch** `WriteMessage.scala:44-50` —
id/source/version/indexName/customMetadata
- [ ] **file** `model.scala:75` — `TarArchiveMetadata.filePathPrefix`
- [ ] **ftp** `model.scala:36` — `FtpFile.permissions: scala Set`, no factory
- [ ] **xml** `model.scala:119` `findAttribute: Option`; `:96`
`attributesList`
- [ ] **mqtt** `model.scala:20` — `MqttMessage.qos` (mqttv5 has `getQoS`)
- [ ] **mqtt-streaming** `model.scala:378,409,442` —
`Subscribe.topicFilters`, `SubAck.returnCodes`, `Unsubscribe.topicFilters`;
`Connect` can't set keepAlive/will from Java
- [ ] **couchbase3** `Document.scala:22,29` — `MutationDocument` /
`MutationBinaryDocument` need `scala.Option` to construct; add `create` +
`getResult: Optional`
- [ ] **solr** `SolrMessages.scala:61` — `WriteMessage` accessors
- [ ] **sqs** `SqsSourceSettings.scala:28` getters; `SqsModel.scala:142,155`
`getResult` erases to `Object`; `SqsModel.scala:152` typo `geResponseMetadata`
- [ ] **huawei-push-kit** `HmsSettings.scala:158,203` —
`getForwardProxy`/`ForwardProxy.create` use `Option`
### Missing parity with scaladsl
- [ ] **s3** — no `chunkSize` / `chunkingParallelism` on javadsl
`multipartUpload*`, `resumeMultipartUpload*`, `multipartCopy`
- [ ] **file** — no javadsl `LogRotatorSink.withTypedSinkFactory`
- [ ] **slick** — no `forDbAndProfile`, no `SlickWithTryResult` equivalent,
`source` only takes a raw SQL string
- [ ] **sse** `javadsl/EventSource.scala:87` — no `retryDelay`
- [ ] **unix-domain-socket** — no javadsl `bindAndHandle`
- [ ] **google-cloud-bigquery-storage** — no javadsl way to supply a custom
`GrpcBigQueryStorageReader`
- [ ] **google-cloud-bigquery** `javadsl/BigQuery.scala:441` —
`createLoadJob[Job]` shadows `model.Job` and `BigQueryMarshallers` has no `Job`
marshaller
### Other
- [ ] **cassandra** `javadsl/CassandraSession.scala:60,79` constructors take
`ExecutionContext`; `CqlSessionProvider.connect()(implicit ec): Future` SPI
- [ ] **amqp** `AmqpConnectionProvider.scala:257` —
`withSSLContext(Option[SSLContext])` only
- [ ] **ironmq** `IronMqSettings.scala:35` `withEndpoint(scaladsl Uri)`
only; `:69` `ConsumerSettings` only reachable via
`IronMqSettings.ConsumerSettings$.MODULE$`
- [ ] **google-cloud-pub-sub-grpc** `PubSubSettings.scala` — no
`withUseTls`, `create(host, port)` hard-codes `useTls = false`
- [ ] **kinesis** `javadsl/KinesisSchedulerSource.scala:31` —
`SchedulerBuilder` is an abstract class, so no lambdas
- [ ] **elasticsearch** `ElasticsearchWriteSettings.scala:19` — `RetryLogic`
SPI requires `FiniteDuration`
- [ ] **s3** `settings.scala:302` — `RetrySettings.default` is uncallable
from Java (`default` is a keyword); no `create(Config)`
- [ ] **s3** `S3Headers.scala:34` — `MetaHeaders.withMetaHeaders(scala Map)`
only
- [ ] **google-cloud-storage** `StorageObject.scala:153,158` —
`withMetadata` / `withAcl` Scala collections only
- [ ] **jms / jakartams** `JmsMessages.scala:881` —
`JmsObjectMessagePassThrough.withProperties(scala Map)` only
- [ ] **huawei-push-kit** `NotificationTarget.scala:35`, **google-fcm**
`NotificationTarget.scala:38` — `ConditionBuilder` only has symbolic `&&` /
`||` / `unary_!`; add `and` / `or` / `not`
- [ ] **slick** `javadsl/package.scala:73` — `nextBytes():
Array[java.lang.Byte]` (boxed `Byte[]`)
- [ ] **mqtt-streaming** `model.scala:97-259` — value classes (incl.
`@InternalApi` `PacketId`, `ControlPacketFlags`) erase to `int` in public
constructors
## 4. Low (summary)
About 120 smaller items, mostly:
- Settings getters returning `Option` / `Seq` / `FiniteDuration` / Scala
`Map` with no `getX` returning `Optional` / `java.util.*` /
`java.time.Duration` (amqp, cassandra, couchbase, elasticsearch, ftp, hbase,
influxdb, ironmq, jms, kinesis, mqtt, mqttv5, mqtt-streaming, s3, sqs,
google-fcm).
- Naming inconsistencies: `apply` vs `create` (kinesisfirehose, influxdb
`Default()`), `grouped` vs `createGrouped` (sqs),
`getObjectMetadataWithHeaders` (s3), `createTableListResponse` (bigquery),
`withOrientDBCredentials(ODatabasePool)` (orientdb).
- Missing convenience overloads (amqp `createSimple(settings)`, pub-sub
`publish` without parallelism, GCS bucket ops without `attributes`, sse without
`lastEventId`, xml `Namespace.create(uri)`, `parserWithContext(Consumer)`).
- `CompletableFuture` vs `CompletionStage` inconsistency (pub-sub-grpc
`subscribe`), `CompletionStage[NotUsed]` mat values (bigquery-storage).
- Deprecated Scala-`Future` variants still present (`subscribeFlowFuture`,
`createShardedFuture`) — candidates for removal in 2.0.0.
- Doc slips (text `TextFlow.encoding` scaladoc), redundant `ActorSystem`
overloads (udp), undeclared return types on public methods (reference, udp).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]