Guice #annotations approach similar to Guice MapBinder approach - java

I am new to Guice DI. And I would like to get my scenario clarified.
To put it simple, Is there any replacement of MapBinder through Guice #annotations?
My Scenario:
Interface A{}
Class A1 implements A{}
Class A2 implements A{}
I would like to Inject the implementation class of A as follows,
if(param = One) then Inject A1 to A
if(param = Two) then Inject A2 to A
I understand that the above could be done with MapBinder, but I would like to do it through annotations as follows,
Class A1 implements A
{
#Inject(param = One)
A1(){}
}
Class A2 implements A
{
#Inject(param = Two)
A2(){}
}
So making the class annotated with params could automatically picks and inject the class based on the parameter (One or Two).
Since #Inject cannot accept params, overriding #Inject would help in this scenario? if so, how do we do so?
Or Is this scenario could only be achieved through binding using MapBinder (The reason why I wouldn't want to use binder is that we would want to define the binding map of key value pair explicitly, but using annotations just simply annotate the implementation class with params - easier maintenance).
Thanks in advance.

To answer your follow-up questino, I believe what you are looking for are named injects. See this example:
public class GuiceNamedTest extends AbstractModule {
public static void main(String[] args) {
Injector i = Guice.createInjector(new GuiceNamedTest());
i.getInstance(InstaceOne.class);
i.getInstance(InstaceTwo.class);
}
#Override
protected void configure() {
Bean beanOne = new Bean();
beanOne.name = "beanOne";
Bean beanTwo = new Bean();
beanTwo.name = "beanTwo";
bind(Bean.class).annotatedWith(Names.named("one")).toInstance(beanOne);
bind(Bean.class).annotatedWith(Names.named("two")).toInstance(beanTwo);
bind(InstaceOne.class);
bind(InstaceTwo.class);
}
public static class Bean {
String name;
}
public static interface A {}
public static class InstaceOne implements A {
#javax.inject.Inject
public InstaceOne(#Named("one") Bean b1) {
System.out.println(b1.name);
}
}
public static class InstaceTwo implements A {
#javax.inject.Inject
public InstaceTwo(#Named("two") Bean b1) {
System.out.println(b1.name);
}
}
}
Here, I am using annotatedWith to name my guice-handled instances. One of them corresponds to the String "one" and the other to "two", analogue to your example.
I can then, in my implementations of A have specific injections of these beans using the #Named annotation.
The result when running above code is:
beanOne
beanTwo
As you can see, it injected the correct instance of my bean into the right implementation.
Hope that helps,
Artur

From the JLS, ยง9.6,
"By virtue of the AnnotationTypeDeclaration syntax, an annotation type declaration cannot be generic, and no extends clause is permitted.
"A consequence of the fact that an annotation type cannot explicitly declare a superclass or superinterface is that a subclass or subinterface of an annotation type is never itself an annotation type. Similarly, java.lang.annotation.Annotation is not itself an annotation type."
So, no, "overriding [sic]" will not help, because no extending type can be an annotation type.

Related

How to make a singleton by generic type with class argument in Spring?

Let's suppose I have a Wrapper with generic type:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Wrapper<T> {
private final Class<T> wrappedClass;
public Wrapper(Class<T> wrappedClass) {
this.wrappedClass = wrappedClass;
}
}
And I want to use this Wrapper with many classes (for example > 100). Is it possible to make Spring create singleton of wrapper for each generic type and pass generic class as parameter to constructor? For example, Spring must always inject the same instance of Wrapper<Foo>. If it is possible, please give example with java code configuration, but not with xml.
If I understood correctly you want to add beans of wrapper dynamically based on some criteria that some beans (like Foo / Bar) adhere to and some don't.
This is a kind of advanced stuff in spring, but in a nutshell you will have to implement a Bean Factory Post Processor that will be called automatically by spring during the startup.
This is a point where you could analyze the beans by iterating over all the "accessible" beans (like Foo / Bar and others) and for beans that should be wrapped you will create a bean definition of the wrapper, despite the fact that the wrapper itself is not a bean.
I've created a simple example to illustrate this. In my sample project I've put everything under package "wrappers":
#Wrappable
public class Foo {
}
#Wrappable
public class Bar {
}
public class ShouldNotBeWrapped {
}
Note that I've put an annotation #Wrappable - a custom annotation that will serve as a "differentiator" of what should be wrapped and what not. The processing of the annotation will be done in Bean Factory Post Processor.
The annotation is nothing special really, it should be acessible in runtime (spring is a runtime framework and be put on classes):
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Wrappable {
}
The java config will add Foo, Bar, ShouldNotBeWrapped as beans and also Bean Factory Post Processor that I'll describe below:
#Configuration
public class WrappersJavaConfig {
#Bean
public Foo foo () {
return new Foo();
}
#Bean
public Bar bar () {
return new Bar();
}
#Bean
public ShouldNotBeWrapped shouldNotBeWrapped () {
return new ShouldNotBeWrapped();
}
#Bean
public WrappersEnrichmentBFPP wrappersEnrichmentBFPP () {
return new WrappersEnrichmentBFPP();
}
}
The Wrapper class itself for the sake of example has toString but it doesn't differ much from your wrapper presented in the question:
public class Wrapper<T> {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
#Override
public String toString() {
return "Wrapper for" + wrapped;
}
}
And the Main class will list all the loaded beans and get their classes + call toString so that we could see that the wrappers are defined correctly:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(WrappersJavaConfig.class);
String[] names = ctx.getBeanDefinitionNames();
for(String name : names) {
Object bean = ctx.getBean(name);
if(bean.getClass().getPackage().getName().startsWith("wrappers")) {
System.out.println(ctx.getBean(name).getClass() + " ==> " + ctx.getBean(name));
}
}
}
}
Sidenote, the "if" condition in the main method is because I don't want to print the beans that spring loads by itself (infra stuff, etc) - only my beans which all reside in package "wrappers" as I've mentioned above.
Now the BeanFactoryPostProcessor - is a regular bean in a sense that it gets registered in the java config and it looks like this (your implementation might be different but the idea is the same):
public class WrappersEnrichmentBFPP implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] bddNames = beanFactory.getBeanDefinitionNames();
for(String bddName : bddNames) {
Object bean = beanFactory.getBean(bddName);
if(bean.getClass().isAnnotationPresent(Wrappable.class)) {
BeanDefinition wrappedBdd = BeanDefinitionBuilder.genericBeanDefinition(Wrapper.class)
.addConstructorArgReference(bddName)
.getBeanDefinition();
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("wrapperFor" + bddName, wrappedBdd);
}
}
}
}
So I'm getting all the beans one by one in for-each loop, then I'm asking whether the bean has an annotation "wrappable" on it in the if condition. If it has - it must be wrapped.
In this case I create an "artificial" bean definition for Wrapper and add a constuctor that will reference my bean that should be wrapped.
Then I register the bean definition by adding it to the application context.
Run the code above and you'll see the output similar to mine:
class wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d ==> wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d#1283bb96
class wrappers.Foo ==> wrappers.Foo#74f0ea28
class wrappers.Bar ==> wrappers.Bar#f6efaab
class wrappers.ShouldNotBeWrapped ==> wrappers.ShouldNotBeWrapped#3c19aaa5
class wrappers.WrappersEnrichmentBFPP ==> wrappers.WrappersEnrichmentBFPP#3349e9bb
class wrappers.Wrapper ==> Wrapper forwrappers.Foo#74f0ea28
class wrappers.Wrapper ==> Wrapper forwrappers.Bar#f6efaab
As you see, two last lines are lines that correspond to the wrapper beans created for the same instances of Foo and Bar but nothing was created for the ShouldNotBeWrapped bean
The APIs used are somewhat obscure and look outdated, but again its pretty advanced stuff and works at the level of spring container infra itself. Having said that, there are a lot of tutorials about BeanFactoryPostProcessor-s.
Since Using BFPPs is not a usual task, and although I've provided the solution, I don't see any real usage of it, wrappers can't be used "instead" of Foo or Bar classes, do not have their APIs, etc. Maybe you could explain why do you need wrappers over some beans. Usually people use Aspects/BeanPostProcessors (not BFPP but BPP) to wrap the class into dynamic proxy (cglib / java.lang.Proxy) and add an additional behavior, stuff like #Transactional, cache handling and so forth is implemented in spring with BeanPostProcessors, so consider checking this direction as well.
It is possible and in fact a feature in spring.
Spring can inject your dependency with the correct generic type.The following example is from spring documentation.
Suppose you have an interface
public interface Store<T>{...}
and two beans. One implements Store,one implemenets Store.
#Configuration
public class MyConfiguration {
#Bean
public StringStore stringStore() {
return new StringStore();
}
#Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
You can declare the type with the correct type parameter and spring will inject the right bean for you.
#Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
#Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean

How to call method from a reference send to annotation in java

I have a Interface I and a Abstract Class A , I have My custom annotation MyAnnotation which should take parameter as subclass S of A, now while processing annotation I want to call method of concrete class S
public interface I{
void m1();
}
public abstract class A implements I {
public abstract void m1();
}
public #interface MyAnnotation {
public Class< ? extends A> ref();
public Class< ? super A> ref2();
}
public S extends A{
public void m1() {}
}
I am annotating method like
#MyAnnotation(ref= new XX() ) or #MyAnnotation(ref= XX.class )
#MyAnnotation(ref= new yy() ) or #MyAnnotation(ref= yy.class )
whichever works
//In spring aspect before processing I am getting method annotation and trying to call m1()
annotation.ref().m1() //Error
annotation.ref2().m1() //Error
You can't use new XX() in an annotation. Annotations parameters can use a very specific set of types:
primitive
String
Class
an Enum
another Annotation
an array of any of the above
See this answer.
So to accomplish what you're trying to accomplish, you'd have to use a class.
You would then have to use reflection to create an instance and invoke the method.
Class<?> clazz = annotation.ref();
I instance = (I) cls.getConstructor().newInstance();
instance.m1();
See this answer.
Your classes must all have no-argument constructors, else you'll only be able to instantiate some this way but not others (leading you to have to conditionally branch based on the class).
You can't do that simply like that. You need an instance of the class first.
If your A class is a Spring's bean, you can inject ApplicationContext and get the bean from there. Then you can call a method.
#Autowired
private ApplicationContext context;
void test(MyAnnotation annotation) {
A bean = context.getBean(annotation.ref());
bean.m1();
}

What is actually involved in a mvp scenario to use google guice?

I am very familiar with using spring to inject using #Bean & #Autowired. I have switched over to looking at guice and I am wondering what is the minimum involved to have it functioning. The following basic example throws a NPE:
import javax.inject.Inject;
public class ClassA {
String a = "test";
#Inject
public ClassA() {
System.out.println(a);
}
public void go() {
System.out.println("two");
}
}
The following class attempting to instantiate a new instance of ClassA:
import javax.inject.Inject;
public class ClassB {
#Inject
ClassA guice;
public ClassB() {
guice.go();
}
public static void main(String[] args) {
ClassB b = new ClassB();
}
}
I have tried all sorts of combinations of the following with no success:
public class SupportModule extends AbstractModule {
#Override
protected void configure() {
bind(ClassA.class);
//bind(ClassA.class).to(ClassB.class);
//others too
}
}
I must be missing a key thing somewhere here, I'm not quite sure where? do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
guice.go(); <= NullPointerException occurs here, obviously the obj is null because my guice setup isn't right
In Spring i can do the following, I assume Guice can aid me in doing this too:
#Bean
public FrameworkProperties properties() {
return new FrameworkProperties();
}
and then just:
#Autowired
FrameworkProperties props;
do I need some manual instantiation of guice/configuration itself? I assume I possibly do.
Yes, you assumed right. You'll have to bootstrap the Injector modules that you have defined using the Guice.createInjector() method. Also, one other thing to note is when using a custom defined constructor like in ClassB, you'll have to use constructor injection. So in order to get this working, ClassB should look like:
public class ClassB {
private ClassA guice;
#Inject //This will inject the dependencies used in the constructor arguments
public ClassB(final ClassA guice) {
this.guice = guice;
guice.go();
}
public static void main(String[] args) {
/**
* If only type to type binding is required, you can skip creating a Module class &
* bootstrap the injector with empty argument createInjector like used below. But, when
* there are other kind of bindings like Type to Implementations defined in modules, you can use:
* final Injector injector1 = Guice.createInjector(new GuiceModule1(), new GuiceModule2());
*/
final Injector injector = Guice.createInjector();
final ClassB b = injector.getInstance(ClassB.class); //This will create dependency graph for you and inject all dependencies used by ClassB and downwards
}
}
Also, you can remove the #Inject annotation used in ClassA's constructor as you are not injecting any external dependencies in that constructor. You can look up the Guice's getting started wiki for more documentation.

Guice - Binding an instance created by assisted injection factory

Let's say that there's class A that's constructor looks something like that:
public A(#Assited long id, #Assisten String name, ServiceA serviceA, ServiceB serviceB)
And there's AFactory:
public interface AFactory{
A create(long id, String name);
}
So to create an instance of A I obviously need to do something like that:
injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");
BUT,
Let's say I have other classes: Class B, Class C and Class D that has a member with type A, for example(with field injection but can be ctor also):
public class B{
#Inject
A a;
}
And I want that the same instance of A will be injected to those classes.
But still have the option to inject another instance of A to other classes (let's say Class E and F).
What is the correct way of doing that?
I just can't think of a clean way to do that.
You could structure your module to use Providers (I'm using #Provides methods below, but you can use full Provider classes or instances if you'd like), and mark the consistent A as #Singleton. If you want two bindings of A (consistent and inconsistent), at least one of them should be marked with a binding annotation; I'm using #Named here out of convenience, but you can use any binding annotation as listed in the docs.
public class AModule extends AbstractModule {
#Override public void configure() {
// Install your AFactory module. Here, injections for AFactory should succeed.
install(new FactoryModuleBuilder().build(AFactory.class));
}
/**
* Provides a singleton #Named("consistent") A.
* Inject #Named("consistent") A into B, C, and D; Guice will cache the instance.
*/
#Provides #Singleton #Named("consistent")
A provideConsistentA(AFactory factory) {
return factory.create(100, "mike");
}
/**
* Provides an unscoped A.
* Inject A without an annotation into E and F; each instance will be separate.
*/
#Provides #Singleton A provideUnscopedA(AFactory factory) {
return factory.create(200, "jeff");
}
}

Spring: Is it possible to have a duplicate constructor with different qualifier while autowiring?

I am trying to autowire a member in a class using the constructor.
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(ClassA objectA) {
myMember = objectA;
}
}
If I have multiple sources that create beans of ClassA, is it possible to have a duplicate constructor definition that instantiates based on the bean that was autowired into this class?
I want to do something like this:
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA) {
myMember = objectA;
}
#Autowire
public MyClass(#Qualifier ("qualifierB") ClassA objectB) {
myMember = objectB;
}
}
I tried using #Qualifier this way, but it didn't work.
Is it possible to do what I'm trying to do, with Spring? How can I disambiguate based on the name (qualifierA) or (qualifierB), if the bean definition is like:
#Bean (name = "qualifierA")
public ClassA getQualifierA() {
...
}
#Bean (name = "qualifierB")
public ClassA getQualifierB() {
...
}
You can't have two constructors with the exact same signature in a single class in Java. Nor any other programming language I've ever encountered. You might use method-injection instead, with two methods (named differently, of course), mark them as #Autowired(required = false) and use the proper #Qualifier(...) to specify the instance you want to inject. You might want to handle the case when both instances are present in the spring context, so no unexpected things happen.
The short answer is: no, that is not possible. In Java you cannot have two constructors with exactly the same signature. And also, you can assign only one value to your "myMember".
However, what are you trying to accomplish here? It seems that in some occasions MyClass needs to use "objectA" and in other occasions, you need "objectB".
For these scenarios, you should not use autowiring (you can't), but simply use explicit wiring:
#Bean
MyClass myObject() {
return new MyClass(qualifierA());
}

Categories

Resources