asEagerSingleton with factory - java

I'm very new to Guice, but I have a singleton that I believe would normally be created thusly:
#Provides
#Singleton
private SomeClass getSomeClass()
{
return someClassFactory(configuration);
}
However, I want this to be eagerly initialized. When I remove the #Singleton annotation and try to bind(SomeClass.class).asEagerSingleton() I get errors:
1) No implementation for SomeClass was bound.
2) A binding to SomeClass was already configured
How can I provide an Eagerly initialized singleton that is constructed with parameters or a factory?

The #Provides annotation is a separate way to configure a binding for SomeClass; it's conflicting with the bind(SomeClass.class).asEagerSingleton() binding.
To fix it, you'll need to write an explicit provider class and bind it using toProvider:
class MyModule extends AbstractModule {
private static class MyProvider implements Provider<SomeClass> {
private final OtherStuff otherStuff;
#Inject
MyProvider(OtherStuff otherStuff) {
// Inject constructor params if your #Provides method took arguments
this.otherStuff = otherStuff;
}
public SomeClass get() {
return new SomeClass(otherStuff);
}
}
protected void configure() {
bind(SomeClass.class).toProvider(MyProvider.class).asEagerSingleton();
}
}

Related

Inject one bean into another with annotations in Guice

I am new to Guice so this might be a basic question. Guice beans get created correctly with below code in Module
public class MyModule extends AbstractModule {
#Override
protected void configure() {
ClassA classAObj = ClassA.standard().build();
bind(ClassA.class).toInstance(classAObj);
ClassB classBObj = new ClassB(classAObj);
bind(ClassA.class).toInstance(classBObj);
}
}
but I want to create beans for ClassA and ClassB using annotations. I tried below code in Module:
public class MyModule extends AbstractModule {
#Provides #Singleton public ClassA getClassA() {
return ClassA.standard().build();
}
#Provides #Singleton public ClassB getClassB() {
Injector injector = Guice.createInjector(new MyModule());
return new ClassB(injector.getInstance(ClassA.class));
}
}
I also tried few other combinations but they don't seem to be working. Can someone please let me know
How to inject bean of ClassA as constructor parameter while creating bean of ClassB using annotations in Guice?
AND/OR
How to set bean of ClassA as class level variable of ClassB(without constructor route)?
You can simply write the following:
#Provides #Singleton
public ClassB getClassB(ClassA classA) {
return new ClassB(classA);
}
By passing ClassA as parameter of getClassB, Guice will consider that ClassB depends on ClassA, and will know that it must call getClassA() before calling getClassB(ClassA).

How can I inject for generic inherited types?

I spent a plenty of time for finding any answers, but I think I have to ask.
I'm using Weld-SE for testing my entities.
I prepared entity randomizer for testing.
abstract class BaseEntityRandomizer<T extends BaseEntity>
implements Randomizer<T> {
#Override public T getRandomValue() {
...
}
}
class MySomeOtherEntityRandomizer
extends BaseEntityRandomizer<MySomeOther> {
#Override public MySomeOther getRandomValue() {
...
}
}
Now, with my test class, I want to inject those randomizers which each matches generic parameters
#ExtendWith(WeldJunit5Extension.class)
#AddPackages({BaseEntityRandomizer.class})
abstract class BaseEntityTest<T extends BaseEntity> {
#Test void doSome() {
}
#Inject
private BaseEntityRandomizer<T> entityRandomizer;
}
class MySomeOtherTest extends BaseEntityTest<MySomeOther> {
...
// I expect an instance of MySomeOtherRandomizer in injected
// into the entityRandomizer field.
}
Subclasses of randomizers and tests are prepared.
But I failed to make it work.
How can I make it work?
I tried with following factory class
class BaseEntityRandomizerFactory {
#Produces
public BaseEntityRandomizer<MySome> produceMySomeRandomizer() {
return new MySomeRandomizer();
}
}
I got
org.jboss.weld.exceptions.IllegalArgumentException:
WELD-001408: Unsatisfied dependencies for type BaseEntityRandomizer<T extends BaseEntity> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject protected transient ....BaseEntityTest.entityRandomizer
at ....BaseEntityTest.entityRandomizer(BaseEntityTest.java:0)
One way to achieve this is to use CDI Programmatic lookup. In your case, I'd start with #Inject Instance<Object> and then you can use subsequent calls to select() and get() methods to pick up whichever bean you desire. Usage looks something like this (assumes existence of beans with types Foo, Bar and List<String>):
#Inject
private Instance<Object> instance;
#Test void doSome() {
// selecting and obtaining instances of beans
Foo foo = entityRandomizer.select(Foo.class).get();
Bar bar = entityRandomizer.select(Bar.class).get();
// in case you need to select a parameterized type from instance, use TypeLiteral
List<String> listBean = entityRandomized..select( new TypeLiteral<List<String>>(){}).get()
}

One dependency in multiple services classes with Dagger 2

I want to inject a custom class as an dependency in different service classes, but I don't get it work. It always ends with a NPE. Here is my example (simple Java SE) ...
My Main class to get everything running
public class Main {
public static void main(String[] args) throws IOException, TimeoutException {
MyApplication MyApp = new MyApplication();
MyApp.execute();
}
}
MyApplication class
public class MyApplication {
private MyApplicationComponent appComponent;
#Inject FooService fooService;
#Inject BarService barService;
#Inject BazService bazService;
public MyApplication() {
component = DaggerMyApplicationComponent.builder().build();
component.inject(this);
}
public void execute() {
fooService.doStuff();
barService.doStuff();
// this will happen in the FooService construct, see below
// bazService.doStuff();
}
}
Component and Module classes as defined in Dagger, without using it the #Inject constructor way
#Singleton
#Component(modules = {MyApplicationModule.class})
public interface MyApplicationComponent {
void inject(MyApplication application);
}
#Module
public class MyApplicationModule {
#Singleton
#Provides
FooService provideFooService() {
return new FooService();
}
#Singleton
#Provides
BarService provideBarService() {
return new BarService();
}
#Provides
BazService provideBazService() {
return new BarService();
}
}
Using the MyApplicationModule and MyApplicationComponent to provide needed dependencies works within the Main.class. I also want to use the BazService within the FooService class. Therefore I use the #Inject way to define it as a dependency with FooService.class.
Using #Inject of BazService within the FooService.class
public class FooService {
#Inject BazService bazService;
public FooService(){}
public doStuff(){
bazService.doStuff();
}
}
Running the Main.class always ends within a NPE, due to undefined bazService in the FooSerivce class. I don't think, that I missed to add an annotation anywhere. I think Dagger will not work this way ... any ideas?
FooService expects bazService to be injected though field injection but you are calling bazService before this happens. If you want to call bazService.doStuff() in FooService's constructor you'll have to use constructor injection.

Error injecting a class with generic type #Inject Guice

I am trying to inject a class of Generic type (say ClassA) in another class (say ClassB) using Guice with #Inject annotation. The code of the class that is being injected is shown below:
public interface InterfaceA<T> {
}
public class ClassA<T> implements InterfaceA<T> {
private final Class<T> data;
private Dependency1 dependency1;
#Inject
public ClassA(Class<T> data, Dependency1 dependency1) {
this.data = data;
this.dependency1 = dependency1;
}
}
Code of ClassB is as follows:
public class ClassB {
private InterfaceA<Entity1> interfaceA;
#Inject
public ClassB(InterfaceA<Entity1> interfaceA) {
this.interfaceA = interfaceA;
}
}
The module class is as follows:
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<InterfaceA<Entity1>>(){}).to(new TypeLiteral<InterfaceA<Entity1>>(){});
}
}
However, when the application starts, it is giving the following error:
ERROR [2017-01-14 19:54:00,646] com.hubspot.dropwizard.guice.GuiceBundle: Exception occurred when creating Guice Injector - exiting
! com.google.inject.CreationException: Unable to create injector, see the following errors:
!
! 1) Could not find a suitable constructor in java.lang.Class. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
! at java.lang.Class.class(Class.java:119)
Any inputs on how to solve this would be really helpful. Thanks in advance.
You can't do this in a declarative way. You have to use provider methods:
public class MyModule extends AbstractModule {
#Override protected void configure() {}
#Provides InterfaceA<Entity1> provideInterfaceAEntity1(Dependency1 dep) {
return new ClassA<Entity1>(Entity1.class, dep);
}
}
This is the only way because you can't automagically inject Class<T> in ClassA.
You need such a method in your Module for each Entity you want to couple with InterfaceA.
I finally found out the solution. Here, instead of injecting Class<T> data in ClassA's constructor, I am injecting TypeLiteral<T> literal and reading the class type from TypeLiteral using it's getRawType() method.
Code for ClassA is as follows:
public class ClassA<T> implements InterfaceA<T> {
private final Class<? super T> data;
private Dependency1 dependency1;
#Inject
public ClassA(TypeLiteral<T> literal, Dependency1 dependency1) {
this.data = literal.getRawType();
this.dependency1 = dependency1;
}
}
The rest of the code for other classes remains same as before.

How can I inject member annotations into my current instantiated object using Guice?

I am trying to inject a custom annotation using the Guice bindInterceptor into my currently instantiated Service.java class. Unfortunately when I call myMethod() the OnAnnotationEvent::invoke method is not called. How can I use Guice to call OnAnnotationEvent::invoke when the #OnAnnotation annotation tag is used on a method in the current class?
My code looks like this:
Service.java
//Instantiated by another service
public class Service extends AbstractVerticle {
private DataAccess dataAccess;
#Inject
public void setDataAccess(DataAccess dataAccess){
this.dataAccess = dataAccess;
}
#Override
public void start() throws Exception {
Guice.createInjector(new DataAccessModule()).injectMembers(this);
myMethod();
}
#MyAnnotation
public void myMethod() {
dataAccess.doStuff();
}
}
DataAccessModule.java
public class DataAccessModule extends AbstractModule {
#Override
protected void configure() {
OnAnnotationEvent onAnnotationEvent = new OnAnnotationEvent();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), onAnnotationEvent);
bind(DataAcess.class).to(DataAccessImpl.class);
}
}
OnAnnotationEvent
public class OnAnnotationEvent implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Annotation called on: " + invocation.getMethod().getName();
return invocation.proceed();
}
}
MyAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {}
I think that your problem is that you creating new injector that does not knows anything about your class. If you just need injector in your class - use #Inject private Injector injector;. If you need to load some aditional modules locally you just need to create child injector :
#Inject private baseInjector;
...
injector = baseInjector.createChildInjector(new Module1(),new Moddule2());
This doesn't work because your Service instance isn't managed by Guice. To make it work you must either create Service with Guice or annotate method doStuff in DataAccessImpl with MyAnnotation.

Categories