This is an automated email from the ASF dual-hosted git repository.

pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-http.git


The following commit(s) were added to refs/heads/main by this push:
     new d81fa589b fix: stop public Scala APIs requiring a private JavaMapping 
implicit (#1340)
d81fa589b is described below

commit d81fa589b493ba08f056fb778e071755a934576c
Author: PJ Fanning <[email protected]>
AuthorDate: Tue Oct 13 05:35:59 2026 +0100

    fix: stop public Scala APIs requiring a private JavaMapping implicit (#1340)
    
    Motivation:
    HttpMessage.attribute and the ResponseEntity.fromJava implicit conversion 
took an
    implicit JavaMapping, which is private[http]. Scala 3.9 warns when user 
code resolves
    it ("Usage of implicit ... which is not accessible here") and Scala 3.10 
will stop
    finding it, so request.attribute(AttributeKeys.remoteAddress) would no 
longer compile.
    
    Modification:
    - Look up the JavaMapping inside attribute and fromJava instead of taking 
it as a
      parameter, matching addAttribute and removeAttribute.
    - Escalate the "which is not accessible here" warning to an error on Scala 
3; the
      deprecation category it belongs to is otherwise silenced.
    - Add HttpModelIntegrationSpec cases, from outside org.apache.pekko.http, 
that read an
      attribute and convert a javadsl ResponseEntity.
    - Add MiMa filters for the removed implicit parameter lists and for the 
internal
      JavaMapping types that no longer escape into the public API.
    
    Result:
    User code can call attribute and use the ResponseEntity conversion on Scala 
3.10.
    This changes the binary signature of both methods, which is acceptable for 
2.0.0.
    
    Tests:
    - sbt "++3.9.0!" http-core/Test/compile without the main change: fails with 
the
      inaccessible-implicit error at the three new call sites
    - sbt "++3.9.0!" Test/compile (all modules) and HttpModelIntegrationSpec: 
pass
    - HttpModelIntegrationSpec on 2.13.18 and 3.3.8: pass
    - sbt http-core/mimaReportBinaryIssues: pass
    - sbt http-core/scalafmtCheckAll http-core/Test/scalafmtCheck 
scalafmtSbtCheck: pass
    
    References:
    Fixes #1056
---
 .../attribute-private-implicit.excludes            | 27 ++++++++++++++++++++++
 .../pekko/http/scaladsl/model/HttpEntity.scala     |  3 +--
 .../pekko/http/scaladsl/model/HttpMessage.scala    |  4 +++-
 .../http/HttpModelIntegrationSpec.scala            | 21 +++++++++++++++++
 project/Common.scala                               |  5 +++-
 5 files changed, 56 insertions(+), 4 deletions(-)

diff --git 
a/http-core/src/main/mima-filters/2.0.x.backwards.excludes/attribute-private-implicit.excludes
 
b/http-core/src/main/mima-filters/2.0.x.backwards.excludes/attribute-private-implicit.excludes
new file mode 100644
index 000000000..3d09e9b41
--- /dev/null
+++ 
b/http-core/src/main/mima-filters/2.0.x.backwards.excludes/attribute-private-implicit.excludes
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# HttpMessage.attribute and ResponseEntity.fromJava no longer take an implicit 
JavaMapping, which is private[http]
+# and so could not be resolved from user code on Scala 3.10 (#1056)
+ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.model.HttpMessage.attribute")
+ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.model.HttpRequest.attribute")
+ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.model.HttpResponse.attribute")
+ProblemFilters.exclude[DirectMissingMethodProblem]("org.apache.pekko.http.scaladsl.model.ResponseEntity.fromJava")
+# With that, the internal JavaMapping types no longer escape into the public 
API
+ProblemFilters.exclude[ClassNoLongerCheckedProblem]("org.apache.pekko.http.impl.util.JavaMapping*")
+ProblemFilters.exclude[ClassNoLongerCheckedProblem]("org.apache.pekko.http.impl.util.J2SMapping*")
+ProblemFilters.exclude[ClassNoLongerCheckedProblem]("org.apache.pekko.http.impl.util.S2JMapping*")
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpEntity.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpEntity.scala
index 435cdedf2..969094811 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpEntity.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpEntity.scala
@@ -274,8 +274,7 @@ sealed trait ResponseEntity extends HttpEntity with 
jm.ResponseEntity {
 }
 
 object ResponseEntity {
-  implicit def fromJava(entity: pekko.http.javadsl.model.ResponseEntity)(
-      implicit m: JavaMapping[pekko.http.javadsl.model.ResponseEntity, 
ResponseEntity]): ResponseEntity =
+  implicit def fromJava(entity: pekko.http.javadsl.model.ResponseEntity): 
ResponseEntity =
     JavaMapping.toScala(entity)
 }
 
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala
index b1963843c..a7e890a6c 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/scaladsl/model/HttpMessage.scala
@@ -149,8 +149,10 @@ sealed trait HttpMessage extends jm.HttpMessage {
     case h: T => h
   }
 
-  def attribute[T](key: jm.AttributeKey[T])(implicit ev: 
JavaMapping[jm.AttributeKey[T], AttributeKey[T]]): Option[T] =
+  def attribute[T](key: jm.AttributeKey[T]): Option[T] = {
+    val ev = implicitly[JavaMapping[jm.AttributeKey[T], AttributeKey[T]]]
     attributes.get(ev.toScala(key)).asInstanceOf[Option[T]]
+  }
 
   /**
    * Returns true if this message is an:
diff --git 
a/http-core/src/test/scala/io/pekko/integrationtest/http/HttpModelIntegrationSpec.scala
 
b/http-core/src/test/scala/io/pekko/integrationtest/http/HttpModelIntegrationSpec.scala
index 936da2abb..cebecd005 100644
--- 
a/http-core/src/test/scala/io/pekko/integrationtest/http/HttpModelIntegrationSpec.scala
+++ 
b/http-core/src/test/scala/io/pekko/integrationtest/http/HttpModelIntegrationSpec.scala
@@ -15,6 +15,8 @@ package io.pekko.integrationtest.http
 
 import com.typesafe.config.{ Config, ConfigFactory }
 
+import java.net.InetSocketAddress
+
 import scala.concurrent.Await
 import scala.concurrent.duration._
 import org.scalatest.BeforeAndAfterAll
@@ -222,5 +224,24 @@ class HttpModelIntegrationSpec extends AnyWordSpec with 
Matchers with BeforeAndA
       ExampleLibrary.contentType(ContentTypes.`text/plain(UTF-8)`)
     }
 
+    "be able to read an attribute without an implicit that is private to Pekko 
HTTP" in {
+      // HttpMessage.attribute used to take an implicit JavaMapping, which is 
private[http].
+      // Scala 3 warns about resolving it from outside the 
org.apache.pekko.http package
+      // and will stop finding it in Scala 3.10.
+      val address = InetSocketAddress.createUnresolved("example.com", 8080)
+      val remote = RemoteAddress(address)
+      val request = HttpRequest().addAttribute(AttributeKeys.remoteAddress, 
remote)
+
+      request.attribute(AttributeKeys.remoteAddress) shouldBe Some(remote)
+      request.attribute(AttributeKey[String]("missing")) shouldBe None
+    }
+
+    "be able to convert a Java ResponseEntity without an implicit that is 
private to Pekko HTTP" in {
+      val javaEntity: org.apache.pekko.http.javadsl.model.ResponseEntity = 
HttpEntity("hello")
+      val entity: ResponseEntity = javaEntity
+
+      entity shouldBe HttpEntity("hello")
+    }
+
   }
 }
diff --git a/project/Common.scala b/project/Common.scala
index abb0a4be9..6e6febe28 100644
--- a/project/Common.scala
+++ b/project/Common.scala
@@ -62,7 +62,10 @@ object Common extends AutoPlugin {
       "-Wconf:msg=type test for.*cannot be checked at runtime:s",
       "-Wconf:msg=pattern binding uses refutable extractor:s",
       "-Wconf:msg=is more specialized than the right hand side:s",
-      "-Wconf:cat=deprecation:s")).value,
+      "-Wconf:cat=deprecation:s",
+      // A public signature must not need an inaccessible implicit; Scala 3.10 
stops resolving those.
+      // Tests in a package outside org.apache.pekko.http (e.g. 
HttpModelIntegrationSpec) catch it.
+      "-Wconf:msg=which is not accessible here:e")).value,
     // Scala 3.8+ migration warnings for syntax that has no replacement which 
also compiles on Scala 2.13.
     // Silence only these, so that other warnings (e.g. `private[this]`) still 
fail the build.
     scalacOptions ++= onlyOnScala38OrLater(Seq(


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to