diff --git a/akka-actor-tests/src/test/java/akka/japi/pf/ReceiveBuilderTest.java b/akka-actor-tests/src/test/java/akka/japi/pf/ReceiveBuilderTest.java index 257384aa56..08f48ab736 100644 --- a/akka-actor-tests/src/test/java/akka/japi/pf/ReceiveBuilderTest.java +++ b/akka-actor-tests/src/test/java/akka/japi/pf/ReceiveBuilderTest.java @@ -191,6 +191,21 @@ public class ReceiveBuilderTest extends JUnitSuite { assertFalse(rcv.onMessage().isDefinedAt(42)); } + private boolean externalPredicateAlwaysTrue(){ + return true; + } + + @Test + public void shouldMatchByExternalPredicate(){ + Receive rcv = ReceiveBuilder.create() + .match(Msg1.class, this::externalPredicateAlwaysTrue, m -> result("match Msg1")) + .build(); + assertTrue(rcv.onMessage().isDefinedAt(new Msg1())); + rcv.onMessage().apply(new Msg1()); + assertEquals("match Msg1", result()); + assertFalse(rcv.onMessage().isDefinedAt(new Msg2("foo"))); + } + @Test public void shouldMatchEquals() { Msg2 msg2 = new Msg2("foo"); diff --git a/akka-actor/src/main/java/akka/japi/pf/ReceiveBuilder.java b/akka-actor/src/main/java/akka/japi/pf/ReceiveBuilder.java index 12cca2fc45..2ca261017c 100644 --- a/akka-actor/src/main/java/akka/japi/pf/ReceiveBuilder.java +++ b/akka-actor/src/main/java/akka/japi/pf/ReceiveBuilder.java @@ -130,6 +130,24 @@ public class ReceiveBuilder { return matchUnchecked(type, predicate, apply); } + /** + * Add a new case statement to this builder. + * + * @param type + * a type to match the argument against + * @param externalPredicate + * a external predicate that will be evaluated if the type matches + * @param apply + * an action to apply to the argument if the type matches and the + * predicate returns true + * @return a builder with the case statement added + */ + public

ReceiveBuilder match(final Class

type, + final java.util.function.BooleanSupplier externalPredicate, + final FI.UnitApply

apply) { + return matchUnchecked(type, externalPredicate, apply); + } + /** * Add a new case statement to this builder without compile time type check. * Should normally not be used, but when matching on class with generic type @@ -164,6 +182,38 @@ public class ReceiveBuilder { return this; } + /** + * Add a new case statement to this builder without compile time type check. + * Should normally not be used, but when matching on class with generic type + * argument it can be useful, e.g. List.class and + * (List<String> list) -> {}. + * + * @param type + * a type to match the argument against + * @param externalPredicate + * a external predicate that will be evaluated if the type matches + * @param apply + * an action to apply to the argument if the type matches and the + * predicate returns true + * @return a builder with the case statement added + */ + @SuppressWarnings("unchecked") + public

ReceiveBuilder matchUnchecked(final Class type, + final java.util.function.BooleanSupplier externalPredicate, + final FI.UnitApply

apply) { + FI.Predicate fiPredicate = new FI.Predicate() { + @Override + public boolean defined(Object o) { + return type.isInstance(o) && + externalPredicate.getAsBoolean(); + } + }; + + addStatement(new UnitCaseStatement(fiPredicate, (FI.UnitApply) apply)); + + return this; + } + /** * Add a new case statement to this builder. * diff --git a/akka-docs/src/test/java/jdocs/actor/InitializationDocTest.java b/akka-docs/src/test/java/jdocs/actor/InitializationDocTest.java index e9e8ae9c64..542c896d1d 100644 --- a/akka-docs/src/test/java/jdocs/actor/InitializationDocTest.java +++ b/akka-docs/src/test/java/jdocs/actor/InitializationDocTest.java @@ -117,6 +117,21 @@ public class InitializationDocTest extends AbstractJavaTest { } } + static class GenericActorWithPredicateAlwaysResponse extends AbstractActor { + private boolean alwaysResponse() { + return true; + } + + @Override + public Receive createReceive() { + return receiveBuilder() + .matchUnchecked(GenericMessage.class, this::alwaysResponse, (GenericMessage msg) -> { + getSender().tell(msg.value.toUpperCase(), getSelf()); + }) + .build(); + } + } + @Test public void testIt() { @@ -158,4 +173,19 @@ public class InitializationDocTest extends AbstractJavaTest { expectMsgEquals("A"); }}; } + + @Test + public void actorShouldAlwaysRespondForEmptyMessage() { + new TestKit(system) {{ + ActorRef genericTestActor = system.actorOf(Props.create(GenericActorWithPredicateAlwaysResponse.class), "genericActorWithPredicateAlwaysResponse"); + GenericMessage emptyGenericMessage = new GenericMessage(""); + GenericMessage nonEmptyGenericMessage = new GenericMessage("a"); + + genericTestActor.tell(emptyGenericMessage, getRef()); + expectMsg(""); + + genericTestActor.tell(nonEmptyGenericMessage, getRef()); + expectMsgEquals("A"); + }}; + } }