javaspringakka

How Lambda operator () -> works?


I would like to understand, how the below code works.

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

@Named
@Scope("prototype")
public class StateOne extends AbstractStateActorActor<StatObject> {

    @Inject
    public StateOne(final Props prop, final StatRegistry statRegistry) {
        super("test", transformationConfig, GenericStateObject.class, statRegistry);
    }
}

@FunctionalInterface
public interface StateHandlerDef {
    Class<? extends AbstractUntypedActor> getHandlerClass();
}

This is the working code.

I would like to understand, How the bean creation work here.

Below code creates a bean.

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

StateOne class has a constructor. But, this creates the bean without passing the constructor arguments. Also, the return type is a function interface which is not implemented by the actual state class and not sure how does it work. This is based an Akka actor model.

AbstractStateActorActor extends AbstractUntypedActor

Here, I would like to set the bean name programmatically instead of setting thru the annotation.

@Bean("test")

If I try BeanPostProcessor for programmatically setting the bean name, it throws error that instance cannot be created using new and should be created with actorof.

Caused by: akka.actor.ActorInitializationException: You cannot create an instance of [com.test.Test] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
    at akka.actor.ActorInitializationException$.apply(Actor.scala:181) ~[akka-actor_2.11-2.4.19.jar:na]

Any help on this?


Solution

  • To understand this think of it this way. The library that you are trying to extend (in this case akka) needs to know the class that is going to handle a state. To do that it gets an instance (bean) of type StateHandlerDef. This instance is created by the lambda expression in this code:

    @Bean
    public StateHandlerDef handler() {
        return () -> StateOne.class;
    }
    

    which is equivalent to something like:

    @Bean
    public StateHandlerDef handler() {
        return new StateHanderDefImpl();
    }
    

    The library will use this to get StateOne.class, for which it will look for a bean and will get it from the dependency injection framework. That bean is defined here:

    @Named
    @Scope("prototype")
    public class StateOne extends AbstractStateActorActor<StatObject> {
    
        @Inject
        public StateOne(final Props prop, final StatRegistry statRegistry) {
            super("test", transformationConfig, GenericStateObject.class, statRegistry);
        }
    }
    

    The DI framework will create a bean from this class by injecting the dependencies it needs in its constructor.