I'm encountering an issue while working with Classic Akka in Java. It seems that Akka is unable to use Java's built-in type casting when creating actors and using .tell().
Below is a simplified version of my code:
Main Class:
import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import akka.actor.Props;
import java.util.UUID;
public class Main {
public static void main(String[] args){
ActorSystem system = ActorSystem.create("system");
ActorRef actorA = system.actorOf(Props.create(ActorA.class , 0), UUID.randomUUID().toString());
actorA.tell(new ActorA.MessageA(7,3),ActorRef.noSender());
}
}
Actor:
import akka.actor.UntypedAbstractActor;
public class ActorA extends UntypedAbstractActor {
private long result;
public ActorA(long StartValue) {
}
//on method: MessageA
public static final class MessageA {
public final double paramD;
public final long paramL;
public MessageA(double paramD, long paramL) {
this.paramD = paramD;
this.paramL = paramL;
}
}
private void onMessageA(double paramD,long paramL) {
System.out.println(paramD);
System.out.println(paramL);
}
public void onReceive(Object message) {
if (message instanceof MessageA MessageAMsg) {
onMessageA(MessageAMsg.paramD, MessageAMsg.paramL);
} else {
unhandled(message);
}
}
}
However, when I run this code, I encounter the following error:
Exception in thread "main" java.lang.IllegalArgumentException: no matching constructor found on class output.ActorA for arguments [class java.lang.Integer]
...
It seems that Akka is expecting an Integer argument instead of a long when creating the ActorA instance. Same goes for Double and Integer. I'm confused because Java usually handles type casting implicitly. Is there a specific reason why Akka behaves this way, and how can I resolve this issue?
Any insights or suggestions would be greatly appreciated. Thank you!
Using Props.create
, as in Props.create(ActorA.class , 0)
entails reflectively constructing the actor, which means that the normal Java type-promotion doesn't come "for free". Such promotion would have to be manually implemented by Props.create
as a special case.
Since the reflective form is not the recommended practice, it's unlikely that that special case would be added (though I suspect that a PR implementing that special case may well be accepted; note that while I am employed by Lightbend, I am not in a position to make any sort of prediction whether this acceptance would happen).
If using Props.create(ActorA.class, () -> new ActorA(0))
, the usual Java promotions would apply. Since main
is static
, the caveat about that approach inadvertently closing over state doesn't apply, but to address that, one could do something like:
public class ActorA extends UntypedAbstractActor {
public static Props props(long startValue) {
return Props.create(ActorA.class, () -> new ActorA(startValue));
}
}