You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pekko.apache.org by he...@apache.org on 2026/07/25 11:30:08 UTC

(pekko) branch java-api-replace-tuple2-with-pair created (now 91f7b8454f)

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

He-Pin pushed a change to branch java-api-replace-tuple2-with-pair
in repository https://gitbox.apache.org/repos/asf/pekko.git


      at 91f7b8454f Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder

This branch includes the following new commits:

     new 91f7b8454f Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pekko.apache.org
For additional commands, e-mail: commits-help@pekko.apache.org


(pekko) 01/01: Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder

Posted by he...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

He-Pin pushed a commit to branch java-api-replace-tuple2-with-pair
in repository https://gitbox.apache.org/repos/asf/pekko.git

commit 91f7b8454f7e4e0c2f94868ba4de6292f392771f
Author: 虎鸣 <he...@alibaba-inc.com>
AuthorDate: Sat Jul 25 19:29:40 2026 +0800

    Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder
    
    Motivation:
    Java users see scala.Tuple2 in their IDE when using FSMTransitionHandlerBuilder,
    which violates the principle of avoiding Scala data structures in Java APIs.
    
    Modification:
    - Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder
    - Update AbstractFSM and PersistentFSMBase to use a proper adapter instead of
      an unsafe .asInstanceOf[TransitionHandler] cast
    - Add MiMa filters for the binary incompatibility
    
    Result:
    Java FSM API no longer exposes scala.Tuple2; uses the established pekko.japi.Pair
    type instead. The adapter is also type-safe (no more unchecked cast).
    
    Tests:
    - sbt "actor-tests / Test / testOnly org.apache.pekko.actor.AbstractFSMActorTest" PASSED
    - sbt "docs / Test / testOnly jdocs.actor.fsm.*" PASSED
    - sbt "persistence / Test / testOnly org.apache.pekko.persistence.fsm.InmemPersistentFSMSpec" PASSED
    - sbt "actor / mimaReportBinaryIssues" PASSED
    
    References:
    Refs #2086
---
 .../pekko/japi/pf/FSMTransitionHandlerBuilder.java | 38 +++++++++++-----------
 .../replace-tuple2-with-pair.excludes              |  5 +++
 .../scala/org/apache/pekko/actor/AbstractFSM.scala | 10 ++++--
 .../pekko/persistence/fsm/PersistentFSMBase.scala  | 10 ++++--
 4 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/actor/src/main/java/org/apache/pekko/japi/pf/FSMTransitionHandlerBuilder.java b/actor/src/main/java/org/apache/pekko/japi/pf/FSMTransitionHandlerBuilder.java
index 4447adfe79..c0793df780 100644
--- a/actor/src/main/java/org/apache/pekko/japi/pf/FSMTransitionHandlerBuilder.java
+++ b/actor/src/main/java/org/apache/pekko/japi/pf/FSMTransitionHandlerBuilder.java
@@ -13,12 +13,12 @@
 
 package org.apache.pekko.japi.pf;
 
+import org.apache.pekko.japi.Pair;
 import org.apache.pekko.japi.function.Effect;
 import org.apache.pekko.japi.function.Predicate;
 import org.apache.pekko.japi.function.Procedure;
 import org.apache.pekko.japi.function.Procedure2;
 import scala.PartialFunction;
-import scala.Tuple2;
 import scala.runtime.BoxedUnit;
 
 /**
@@ -28,7 +28,7 @@ import scala.runtime.BoxedUnit;
  */
 public class FSMTransitionHandlerBuilder<S> {
 
-  private final UnitPFBuilder<Tuple2<S, S>> builder = new UnitPFBuilder<Tuple2<S, S>>();
+  private final UnitPFBuilder<Pair<S, S>> builder = new UnitPFBuilder<Pair<S, S>>();
 
   /**
    * Add a case statement that matches on a from state and a to state.
@@ -41,17 +41,17 @@ public class FSMTransitionHandlerBuilder<S> {
   public FSMTransitionHandlerBuilder<S> state(
       final S fromState, final S toState, final Effect apply) {
     builder.match(
-        Tuple2.class,
-        new Predicate<Tuple2>() {
+        Pair.class,
+        new Predicate<Pair>() {
           @Override
-          public boolean test(Tuple2 t) {
-            return (fromState == null || fromState.equals(t._1()))
-                && (toState == null || toState.equals(t._2()));
+          public boolean test(Pair t) {
+            return (fromState == null || fromState.equals(t.first()))
+                && (toState == null || toState.equals(t.second()));
           }
         },
-        new Procedure<Tuple2>() {
+        new Procedure<Pair>() {
           @Override
-          public void apply(Tuple2 t) throws Exception {
+          public void apply(Pair t) throws Exception {
             apply.apply();
           }
         });
@@ -69,21 +69,21 @@ public class FSMTransitionHandlerBuilder<S> {
   public FSMTransitionHandlerBuilder<S> state(
       final S fromState, final S toState, final Procedure2<S, S> apply) {
     builder.match(
-        Tuple2.class,
-        new Predicate<Tuple2>() {
+        Pair.class,
+        new Predicate<Pair>() {
           @Override
-          public boolean test(Tuple2 t) {
-            return (fromState == null || fromState.equals(t._1()))
-                && (toState == null || toState.equals(t._2()));
+          public boolean test(Pair t) {
+            return (fromState == null || fromState.equals(t.first()))
+                && (toState == null || toState.equals(t.second()));
           }
         },
-        new Procedure<Tuple2>() {
+        new Procedure<Pair>() {
           @Override
-          public void apply(Tuple2 t) throws Exception {
+          public void apply(Pair t) throws Exception {
             @SuppressWarnings("unchecked")
-            S sf = (S) t._1();
+            S sf = (S) t.first();
             @SuppressWarnings("unchecked")
-            S st = (S) t._2();
+            S st = (S) t.second();
             apply.apply(sf, st);
           }
         });
@@ -96,7 +96,7 @@ public class FSMTransitionHandlerBuilder<S> {
    *
    * @return a PartialFunction for this builder.
    */
-  public PartialFunction<Tuple2<S, S>, BoxedUnit> build() {
+  public PartialFunction<Pair<S, S>, BoxedUnit> build() {
     return builder.build();
   }
 }
diff --git a/actor/src/main/mima-filters/2.0.x.backwards.excludes/replace-tuple2-with-pair.excludes b/actor/src/main/mima-filters/2.0.x.backwards.excludes/replace-tuple2-with-pair.excludes
new file mode 100644
index 0000000000..5ea8aa4423
--- /dev/null
+++ b/actor/src/main/mima-filters/2.0.x.backwards.excludes/replace-tuple2-with-pair.excludes
@@ -0,0 +1,5 @@
+# Replace scala.Tuple2 with pekko.japi.Pair in FSMTransitionHandlerBuilder
+# https://github.com/apache/pekko/issues/2086
+ProblemFilters.exclude[IncompatibleResultTypeProblem]("org.apache.pekko.japi.pf.FSMTransitionHandlerBuilder.build")
+ProblemFilters.exclude[IncompatibleSignatureProblem]("org.apache.pekko.japi.pf.FSMTransitionHandlerBuilder.build")
+ProblemFilters.exclude[IncompatibleMethTypeProblem]("org.apache.pekko.japi.pf.FSMTransitionHandlerBuilder.state")
diff --git a/actor/src/main/scala/org/apache/pekko/actor/AbstractFSM.scala b/actor/src/main/scala/org/apache/pekko/actor/AbstractFSM.scala
index fd26155ced..e8e33c15e8 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/AbstractFSM.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/AbstractFSM.scala
@@ -17,6 +17,7 @@ import scala.concurrent.duration.FiniteDuration
 import scala.jdk.DurationConverters._
 
 import org.apache.pekko
+import pekko.japi.Pair
 import pekko.japi.function.{ Effect, Function2, Predicate, Predicate2, Procedure, Procedure2, Procedure3 }
 
 /**
@@ -169,8 +170,13 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
    * <b>Multiple handlers may be installed, and every one of them will be
    * called, not only the first one matching.</b>
    */
-  final def onTransition(transitionHandlerBuilder: FSMTransitionHandlerBuilder[S]): Unit =
-    super.onTransition(transitionHandlerBuilder.build().asInstanceOf[TransitionHandler])
+  final def onTransition(transitionHandlerBuilder: FSMTransitionHandlerBuilder[S]): Unit = {
+    val pf = transitionHandlerBuilder.build()
+    super.onTransition(new TransitionHandler {
+      def isDefinedAt(in: (S, S)): Boolean = pf.isDefinedAt(Pair(in._1, in._2))
+      def apply(in: (S, S)): Unit = pf(Pair(in._1, in._2))
+    })
+  }
 
   /**
    * Add a handler which is called upon each state transition, i.e. not when
diff --git a/persistence/src/main/scala/org/apache/pekko/persistence/fsm/PersistentFSMBase.scala b/persistence/src/main/scala/org/apache/pekko/persistence/fsm/PersistentFSMBase.scala
index 1e7455a0fb..4a47db624a 100644
--- a/persistence/src/main/scala/org/apache/pekko/persistence/fsm/PersistentFSMBase.scala
+++ b/persistence/src/main/scala/org/apache/pekko/persistence/fsm/PersistentFSMBase.scala
@@ -23,6 +23,7 @@ import language.implicitConversions
 import org.apache.pekko
 import pekko.actor._
 import pekko.japi.function.{ Effect, Function2, Predicate, Predicate2, Procedure, Procedure2, Procedure3 }
+import pekko.japi.Pair
 import pekko.japi.pf.{ FSMTransitionHandlerBuilder, UnitMatch, UnitPFBuilder }
 import pekko.routing.{ Deafen, Listen, Listeners }
 
@@ -850,8 +851,13 @@ abstract class AbstractPersistentFSMBase[S, D, E] extends PersistentFSMBase[S, D
    * <b>Multiple handlers may be installed, and every one of them will be
    * called, not only the first one matching.</b>
    */
-  final def onTransition(transitionHandlerBuilder: FSMTransitionHandlerBuilder[S]): Unit =
-    onTransition(transitionHandlerBuilder.build().asInstanceOf[TransitionHandler])
+  final def onTransition(transitionHandlerBuilder: FSMTransitionHandlerBuilder[S]): Unit = {
+    val pf = transitionHandlerBuilder.build()
+    onTransition(new TransitionHandler {
+      def isDefinedAt(in: (S, S)): Boolean = pf.isDefinedAt(Pair(in._1, in._2))
+      def apply(in: (S, S)): Unit = pf(Pair(in._1, in._2))
+    })
+  }
 
   /**
    * Add a handler which is called upon each state transition, i.e. not when


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pekko.apache.org
For additional commands, e-mail: commits-help@pekko.apache.org