using guice injection with actor throws null pointer - java

I'm getting null pointer exception on the field injection of a server which is started as an akka actor.
Schedular part:
private ActorRef myActor = Akka.system().actorOf(
new Props(Retreiver.class));
#Override
public void onStart(Application app) {
log.info("Starting schedular.....!");
Akka.system()
.scheduler()
.schedule(Duration.create(0, TimeUnit.MILLISECONDS),
Duration.create(30, TimeUnit.MINUTES), myActor, "tick",
Akka.system().dispatcher());
}
Retreiver class part:
public class Retreiver extends UntypedActor {
private Logger.ALogger log = Logger.of(Retreiver .class);
#Inject
private myDataService dataService;
#Override
public void onReceive(Object arg0) throws Exception {
if (0 != dataService.getDataCount()) {
....
....
....
}
}
I'm getting null for dataService. Please advice me on this.
Thanks.

For anyone who needs this:
public class GuiceInjectedActor implements IndirectActorProducer {
final Injector injector;
final Class<? extends Actor> actorClass;
public GuiceInjectedActor(Injector injector, Class<? extends Actor> actorClass) {
this.injector = injector;
this.actorClass = actorClass;
}
#Override
public Class<? extends Actor> actorClass() {
return actorClass;
}
#Override
public Actor produce() {
return injector.getInstance(actorClass);
}
}
AND
Akka.system().actorOf(Props.create(GuiceInjectedActor.class, INJECTOR,Retreiver.class))
Thats it...!!!

You're getting the NullPointerException because Akka is instantiating your Retriever actor and not Guice. You need to get Guice to construct your instance and then pass that to Akka, IndirectActorProducer can help you achieve this, e.g.:
class RetrieverDependencyInjector implements IndirectActorProducer {
final Injector injector;
public RetrieverDependencyInjector(Injector injector) {
this.injector = injector;
}
#Override
public Class<? extends Actor> actorClass() {
return Retriever.class;
}
#Override
public Retriever produce() {
return injector.getInstance(Retriever.class);
}
}
Note that produce() must create a new Actor instance each time it is invoked, it cannot return the same instance.
You can then get Akka to retrieve your actor through the RetrieverDependencyInjector, e.g.:
ActorRef myActor = Akka.system().actorOf(
Props.create(RetrieverDependencyInjector.class, injector)
);
UPDATE
I thought about you comment further, you might be able to turn RetrieverDependencyInjector into a GenericDependencyInjector by providing the class of the Actor you want as a constructor parameter, that perhaps will allow you to do something like:
Props.create(GenericDependencyInjector.class, injector, Retriever.class)
I haven't tried this, but it might give you a starting point.

There can be other ways, eg, you can put a static injector handle in Boot or Some-Injector-Holder-class, and inject when you create the actor by call the inherited method: preStart ()
public class Retreiver extends UntypedActor {
private Logger.ALogger log = Logger.of(Retreiver .class);
#Override
public void preStart () {
super.preStart ();
Boot.injector.injectMembers (this);
//Some-Injector-holder.injectMembers (this);
}
#Inject
private myDataService dataService;
#Override
public void onReceive(Object arg0) throws Exception {
if (0 != dataService.getDataCount()) {
....
....
....
}
}
and also, you can also inject the injector in actor provider to initialize the actor by the injector in a scope of UntypedActorFactory:
public class InjectingActorProvider implements Provider<ActorRef> {
#Inject
private Injector injector;
#SuppressWarnings("serial")
#Override
public final ActorRef get() {
Props props = new Props(new UntypedActorFactory() {
#Override
public Actor create() {
return injector.getInstance(actorClass);
}
});
props = props.withRouter(...);
props = props.withDispatcher(...);
actor = system.actorOf(props, actorName);
return actor;
}
}

Related

How can await util all messages was processed by actor in unit test?

I'm using Akka actor in our product. We wrote some code:
#Singleton
public class SingletonObj {
private Map<String, Integer> cached = new HashMap();
public void set(String key, Integer value) {
cached.put(key, value);
}
public void delete(String key){
cached.delete(key}
}
}
public class MyActor extends AbstractActor implements InjectedActorSupport {
#Inject SingletonObj singletonObj;
public static Props props(Injector injector) {
return Props.create(MyActor.class, injector);
}
public MyActor(Injector injector) {
this.injector = injector;
receive(ReceiveBuilder.create()
.match(AddEvent.class, this::addEvent)
.match(DeteteEvent.class, this::deleteEvent))
.build());
}
private void addEvent(AddEvent addEvent) {singletonObj.set(addEvent.key, addEvent.value);}
private void deteleEvent(DeteteEvent event){singletonObj.detele(event.key);}
}
public class Controller {
private Injector injector;
private ActorSystem actorSystem;
public void handleAdd()...
public void handleDelete()...
}
Then when I wrote some test in junit for these class
#Test public void testMethod(){
sendAddRequest(...);
sendDeteleRequest(...)
...
...
assertThat(singletonObj.get("someString")).isEqual(42)
}
Then this test is unreliable because when I do assertion, then all events was not handled yet.
How can I wait utils all events in actor system finish?
Import the below package and then you can await till you process all the events or the test will fail after timeout.
testCompile 'org.awaitility:awaitility:3.1.0'
import org.awaitility.Awaitility;
And before your assertThat use
await().pollInterval(5, TimeUnit.MILLISECONDS).until(() -> !isProcessed());
The isProcessed method will look something like below
protected Callable<Boolean> isProcessed() {
return () -> {
return singletonObj.getCacheCount()==2;
};
}
Regards,
Vinoth

Android injecting class return null

I'm using JobQueue library and i can successful inject some class such as GithubService to that for example:
public interface GithubService {
#GET("repositories")
Call<List<GithubRepo>> getAllRepositories();
}
now i'm trying to inject other class as RxBus
public interface Bus {
void register(#NonNull Object observer);
<T> CustomSubscriber<T> obtainSubscriber(#NonNull Class<T> eventClass, #NonNull Consumer<T> receiver);
<T> void registerSubscriber(#NonNull Object observer, #NonNull CustomSubscriber<T> subscriber);
void unregister(#NonNull Object observer);
void post(#NonNull Object event);
}
into job file, but i get null
job class:
public class GetLatestRepositories extends Job implements JobManagerInjectable {
#Inject
transient GithubService githubService;
#Inject
transient Bus eventBus;
private Call<List<GithubRepo>> repositoryCall;
public GetLatestRepositories() {
super(new Params(JobPriority.MID).requireNetwork().persist());
eventBus.register(this); /* IS NULL*/
}
#Override
public void onAdded() {
}
...
#Override
public void inject(ApplicationComponent component) {
component.inject(this);
}
}
ApplicationComponent
#ActivitiesScope
#Component(dependencies = GithubApplicationComponent.class)
public interface ApplicationComponent {
void inject(ActivityRegister activityRegister);
void inject(ActivityStartUpApplication activityStartUpApplication);
void inject(GetLatestRepositories getLatestRepositories);
}
GithubApplicationComponent
#AlachiqApplicationScope
#Component(
modules = {
UserInformationModule.class,
NetworkServiceModule.class,
PicassoModule.class,
JobManagerModule.class,
RxModule.class,
ActivityModule.class
}
)
public interface GithubApplicationComponent {
Picasso getPicasso();
GithubService getGithubService();
JobManager getJobManager();
Bus getBus();
}
RxModule
#Module
public class RxModule {
#Provides
#AlachiqApplicationScope
public Bus getBus() {
return new RxBus();
}
}
RxBux files
In RxModule instead of:
return new RxBus();
Do:
return BusProvider.getInstance();

Why am I getting "classes must have either one (and only one) constructor" error?

I have been trying to get Guice working but end up with this:
Classes must have either one (and only one) constructor
My interface:
public interface AddrBookStore {
public Contact getContactByKey(String key);
public void addContact(Contact c);
}
The implementation:
public class RdbmsBasedAddrBookStore implements AddrBookStore {
private Connection connection;
public RdbmsBasedAddrBookStore(Connection connection) {
this.connection = connection;
}
#Override
public Contact getContactByKey(String key) throws AddrBookException
{}
#Override
public void addContact(Contact c) throws AddrBookException
{}
}
The binding module:
public class ABguiceConfingModule extends AbstractModule {
#Override
protected void configure() {
bind(AddrBookStore.class).to(RdbmsBasedAddrBookStore.class);
}
}
The AddrBook client where I am injecting:
public class AddrBook {
private AddrBookStore store;
#Inject
public AddrBook(AddrBookStore store)
{
this.store = store;
}
... other methods;
}
And my main:
public class App
{
public static void main( String[] args ) throws Exception
{
Injector injector = Guice.createInjector(new ABguiceConfingModule() );
AddrBookStore store = injector.getInstance( AddrBookStore.class );
AddrBook book = new AddrBook(store);
AddrBookCLI cli = new AddrBookCLI(book);
cli.interact(new InputStreamReader(System.in), new OutputStreamWriter(System.out));
}}
After all this, I'm getting this error:
1) Could not find a suitable constructor in addrbook.store.RdbmsBasedAddrBookStore. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
[ERROR] at addrbook.store.RdbmsBasedAddrBookStore.class(RdbmsBasedAddrBookStore.java:23)
[ERROR] at addrbook.ABguiceConfingModule.configure(ABguiceConfingModule.java:13)
I have experience with Spring and not with Guice. Where am I going wrong here?
You haven't set up the primary dependency for AddrBookStore. You need to have a binding for Connection, and then you need to annotate the constructor with #Inject.
You've set up the AddrBookStore class but clearly it's wrapping an Rdbms... except you haven't set up the Rdbms.
There are lots of ways to do this in Guice, in this case I would probably do it with a Provider<Connection>, that way you have an entire class to put the code for spinning up your connection to the database, so something like:
public class ConnectionProvider implements Provider<Connection> {
public Connection get() {
// put your code that connects to the database here
}
}
Then your module would be:
public class ABguiceConfingModule extends AbstractModule {
#Override
protected void configure() {
bind(AddrBookStore.class).to(RdbmsBasedAddrBookStore.class);
bind(Connection.class).toProvider(ConnectionProvider.class);
}
}
And then finally your AddrBookStore:
public class RdbmsBasedAddrBookStore implements AddrBookStore {
private Connection connection;
#Inject
public RdbmsBasedAddrBookStore(Connection connection) {
this.connection = connection;
}
#Override
public Contact getContactByKey(String key) throws AddrBookException
{}
#Override
public void addContact(Contact c) throws AddrBookException
{}
}
Had this error message because I forget to add annotation #Inject on constructor. public AddrBook(AddrBookStore store) in the case of this question.

why does Guice create a new instance for my singleton?

I have this guice code
public class MainModule extends AbstractModule {
#Override
protected void configure() {
bind(GlobalSettings.class).toProvider(GlobalSettingsProvider.class).in(Singleton.class);
}
and
public class GlobalSettingsProvider implements Provider<GlobalSettings> {
#Override
public GlobalSettings get() {
GlobalSettings globalSettings = new GlobalSettings();
globalSettings.isDummyRun = Boolean.parseBoolean(System.getProperty("isDummyRun", "false"));
globalSettings.inputFlavor = System.getProperty("input_flavor", "none");
}
}
and
public class A(){
public A() {
this.injector = Guice.createInjector(new MainModule());
injector.getInstance(IHttpClientReRunWrapper.class);
globalSettings = injector.getInstance(GlobalSettings.class);
resultsComparerRunner1 = injector.getInstance(ResultsComparerRunner.class);
resultsComparerRunner2 = injector.getInstance(ResultsComparerRunner.class);
resultsComparerRunner3 = injector.getInstance(ResultsComparerRunner.class);
}
}
and
public class ResultsComparerRunner(){
public class ResultsComparerRunner(){
initStaticFromInjector();
}
private void initStaticFromInjector() {
routingResponseShortRepository = injector.getInstance(IRoutingResponseShortRepository.class);
globalSettings = injector.getInstance(GlobalSettings.class); //verify only one injector per run
}
why do I see globalSettings in instance of A and in instance of ResultsComparerRunner are different?
I wanted it to be singelton
I was curious about the behavior of provider binding plus singleton, so I created a test-gist based on your code:
#Test
public void execute() {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(GlobalSettings.class).toProvider(GlobalSettingsProvider.class).in(Singleton.class);
}
});
GlobalSettings g1 = injector.getInstance(GlobalSettings.class);
GlobalSettings g2 = injector.getInstance(GlobalSettings.class);
assertThat(g1).isSameAs(g2);
}
Result: green. Meaning that your module setup is working, your problem must lie somewhere else. How do you pass the injector to the ResultsComparerRunner? Is this really the injector containing the singleton definition?
My problem was that I called
injector = Guice.createInjector(new MainModule());
twice in two different places-
which created two singletons.

Conditional matching in Google Guice

I have a MethodInterceptor bound to methods in a class in order to do some simple logic before on the data before the class gets to touch it.
However, teh class itself makes calls to some of its own intercepted methods, but at that point I don't need to re-run that logic anymore.
public class MyModule extends AbstractModule {
#Override
public void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), new MyInterceptor());
}
}
public class MyInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// logic
}
}
public MyClass {
#MyAnnotation
void foo() {
bar();
}
#MyAnnotation
void bar() {
}
}
Is there a way for the call for bar within foo to not be itnercepted?
To be honest, the easiest solution is to simply avoid the problem by never calling another public/annotated method of the same class from within the class:
public class MyClass {
#MyAnnotation
public void foo() {
doBar();
}
#MyAnnotation
public void bar() {
doBar();
}
private void doBar() {
//doesn't go through interceptor
}
}
If for some reason that's not an option, then you might look at this approach. More expressive AOP libraries like AspectJ give you a greater level of flexibility for defining a pointcut.
In Guice, the pointcut is simply a method with an annotation belonging to an instance instantiated by Guice. So this logic has to be moved to the interceptor itself.
One approach for doing so might be to use a ThreadLocal to track entries into the interceptor. Extending something like this might be a start:
public abstract class NonReentrantMethodInterceptor implements MethodInterceptor {
private final ThreadLocal<Deque<Object>> callStack = new ThreadLocal<>();
#Override
public final Object invoke(MethodInvocation invocation) throws Throwable {
Deque<Object> callStack = this.callStack.get();
if (callStack == null) {
callStack = new LinkedList<>();
this.callStack.set(callStack);
}
try {
return invokeIfNotReentrant(callStack, invocation);
} finally {
if (callStack.isEmpty()) {
this.callStack.remove();
}
}
}
private final Object invokeIfNotReentrant(Deque<Object> callStack, MethodInvocation invocation) throws Throwable {
Object target = invocation.getThis();
if (callStack.isEmpty() || callStack.peek() != target) {
//not being called on the same object as the last call
callStack.push(target);
try {
return doInvoke(invocation);
} finally {
callStack.pop();
}
} else {
return invocation.proceed();
}
}
protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
}
This uses a thread local stack to track the stack of calls into the interceptor. When the last call into this interceptor targeted the same object, it calls proceed() and bypasses the interceptor. When this is the first call into the interceptor, or if the last call was not targeting the same object, it applies the interceptor.
Then the actual logic you would want to apply when the interceptor is active would go into doInvoke().
Example usage:
public class NonReentrantTester {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new Module());
MyClass instance = injector.getInstance(MyClass.class);
instance.foo();
}
static class Module extends AbstractModule {
#Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrintsFirstInvocation.class),
new PrintsFirstInvocationInterceptor());
}
}
public static class MyClass {
#PrintsFirstInvocation
void foo() {
bar();
}
#PrintsFirstInvocation
void bar() {
}
}
public static class PrintsFirstInvocationInterceptor extends NonReentrantMethodInterceptor {
#Override
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod());
return invocation.proceed();
}
}
#BindingAnnotation
#Target({FIELD, PARAMETER, METHOD})
#Retention(RUNTIME)
public #interface PrintsFirstInvocation {
}
}

Categories

Resources