Google Guice - Use generic as parameter of injected field - java

I want to use a generic parameter of a class for a field that is injected, but guice complains about a unbound key. Is it possible to inject the field in Test2?
Example:
public static class Test1<T1> {
}
public static class Test2<T2> {
#Inject
public Test1<T2> test;
}
public static void main(String[] args) throws Exception {
Injector injector = Jsr250.createInjector(Stage.PRODUCTION, new TestModule());
Test2<String> test = injector.getInstance(Key.get(new TypeLiteral<Test2<String>>(){}));
}
private static class TestModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<Test1<String>>(){}).toInstance(new Test1<String>());
bind(new TypeLiteral<Test2<String>>(){}).toInstance(new Test2<String>());
}
}

Well, this is overkill for java generics. You code would not work even without injection, cuz Test1<T2> cannot match Test1<String>. You should consider different approach, try to use Annotation binding like:
public static class Test2 {
#Inject #Named("T2")
public Test1<someGenericInterface> test;
}
bind(new TypeLiteral<Test1<someGenericInterface>>(){}).annotatedWith(Names.named("T2")).toInstance(new Test1<T2>()); //T2 implements someGenericInterface
bind(new TypeLiteral<Test1<someGenericInterface>>(){}).annotatedWith(Names.named("T1")).toInstance(new Test1<T1>()); //T1 implements someGenericInterface
or implement specific Provider Provider bindings or use MapBinder

Related

How to inject bean via generic variable in spring

I have problem with injecting bean with generic types. Look at the example. I will inject to the service a repository which types takes from App class. Now i have exception:
No qualifying bean of type 'asd.IRepository' available: expected single matching bean but found 2: a,b
asd here is package, just for tests.
What can I do in this situation? Is any way to makes it?
public interface IRepository<T, V> {
void print();
}
#Component
public class A implements IRepository<String,String> {
#Override
public void print() {
System.out.println("A");
}
}
#Component
public class B implements IRepository<Double,String> {
#Override
public void print() {
System.out.println("A");
}
}
#Service
public class ServiceABC<V, T> {
#Autowired
private IRepository<V,T> repo;
public void print(){
repo.print();
}
}
#Controller
public class App {
#Autowired
private ServiceABC<String, String> serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print();
}
It looks like you don't know in advance which implementation of your IRepository interface you will need. And you will know that at runtime. In this case it is a typical case for Factory pattern where you will have a IRepositoryFactory that will have a method thhat retrieves specific implementation by type (for example IRepositoryFactory.getInstance(String type); So in your ServiceABC you may use the IRepository to get specific bean at runtime. So Factory pattern may be an answer to your question. I also wrote an article that deals with this type of problem and proposes the idea of self-populating Factory (using Open source library that provides such utility). Here is the link to the article: Non-intrusive access to "Orphaned" Beans in Spring framework
You have to name your components and autowire by name:
#Component("A")
public class A implements IRepository<String,String> {...}
#Component("B")
public class B implements IRepository<Double,String> {...}
[...]
#Autowired
#Qualifier("B")
private IRepository repo;
Something like that?
#Controller
public class RepositoryFactory {
#Autowired
private IRepository<String, String> a;
#Autowired
private IRepository<Double, String> b;
public IRepository getRepository(String className) {
if(className.equalsIgnoreCase("a")) {
return a;
} else if(className.equalsIgnoreCase("b")) {
return b;
}
return null;
}
}
#Service
public class ServiceABC {
#Autowired
private RepositoryFactory repositoryFactory;
public void print(String className){
repositoryFactory.getRepository(className).print();
}
}
#Controller
public class App {
#Autowired
private ServiceABC serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print(A.class.getSimpleName());
}
}s

How to collect several interfaces into a Collection in HK2?

I have my AbstractBinder and I bind several classes with the same interface. Let's say I bind Fish and Cat which both implement Animal interface.
What is the easiest/proper way of injecting them into a bean which takes Collection<Animal> ?
PS: Spring has equivalent in simply #Autowire List<Animal> and the collection is created and populated by Spring.
HK2 has IterableProvider<T>, as mentioned here in the documentation. You can get the service by name, by qualifier annotation, or just iterate over them, as it's an Iterable. Just for fun, here is a test.
public class IterableProviderTest {
public static interface Service {}
public static class ServiceOne implements Service {}
#QualAnno
public static class ServiceTwo implements Service {}
#Qualifier
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public static #interface QualAnno {
public static class Instance
extends AnnotationLiteral<QualAnno> implements QualAnno {
public static QualAnno get() {
return new Instance();
}
}
}
public class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(ServiceOne.class).to(Service.class).named("one");
bind(ServiceTwo.class).to(Service.class).qualifiedBy(QualAnno.Instance.get());
}
}
#Inject
private IterableProvider<Service> services;
#Test
public void test_IterableProvider() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new Binder());
locator.inject(IterableProviderTest.this);
assertEquals(2, services.getSize());
Service serviceOne = services.named("one").get();
assertTrue(serviceOne instanceof ServiceOne);
Service serviceTwo = services.qualifiedWith(QualAnno.Instance.get()).get();
assertTrue(serviceTwo instanceof ServiceTwo);
}
}
UPDATE
For a List<Service> (to avoid HK2 InterablProvider), the only think I can think of is to use a Factory and inject the IterableProvider into it, and from there return the list. For example
public class Binder extends AbstractBinder {
#Override
protected void configure() {
...
bindFactory(ListServiceFactory.class).to(new TypeLiteral<List<Service>>(){});
}
}
public static class ListServiceFactory implements Factory<List<Service>> {
#Inject
private IterableProvider<Service> services;
#Override
public List<Service> provide() {
return Lists.newArrayList(services);
}
#Override
public void dispose(List<Service> t) {}
}
Yeah it's a little bit of extra work.
In the latest release of hk2 (2.4.0) you can
#Inject Iterable<Foo> foos;
That allows you to keep your pojo's without any hk2 API in them.
For more information see: Iterable Injection

Injecting method interceptors in Guice

I've searched all over the web for it and everyone (including) google suggests using requestInjection() but I still don't understand how to use it. I have a class that implements Method Interceptor:
public class CacheInterceptor implements MethodInterceptor {
private ILocalStore localStore;
private IRemoteStore remoteStore;
private CacheUtils cacheUtils;
public CacheInterceptor() {
}
#Inject
public CacheInterceptor(ILocalStore localStore, CacheUtils cacheUtils, IRemoteStore remoteStore) {
this.localStore = localStore;
this.cacheUtils = cacheUtils;
this.remoteStore = remoteStore;
}
}
And I have 3 classes that extends AbstractModule.
public class CacheUtilModule extends AbstractModule {
#Override
protected void configure() {
bind(CacheUtils.class);
}
}
public class LocalCachingModule extends AbstractModule {
#Override
public void configure() {
bind(ILocalStore.class).to(LocalStore.class);
}
}
public class RedisCachingModule extends AbstractModule {
#Override
protected void configure() {
bind(IRemoteStore.class).to(RemoteStore.class);
}
}
And I did the following for binding the interceptor
public class RequestScopedCachingModule extends AbstractModule {
#Override
public void configure() {
install(new CacheUtilModule());
install(new LocalCachingModule());
install(new RedisCachingModule());
MethodInterceptor interceptor = new CacheInterceptor();
requestInjection(interceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Cacheable.class),
interceptor);
}
}
So basically, I want to inject the localStore, remoteStore, and cacheUtils in my MethodInterceptor with my own implementation mapped out in my 3 modules. But this didn't work. I guess I am just confused with requestInjection(). In the documentation, requestInjection does this
Upon successful creation, the Injector will inject instance fields and methods of the given object.
But where do we specify the mapping between the interface and the implementation class? How can I get what I wanted to do to work?
requestInjection will only inject fields and methods - it won't invoke the constructor and doesn't know anything about the #Inject annotations on your constructor. If you add #Inject to all of your fields your code should work as you expect.

Inject a TypeListener

I have this scenario where I want to inject a TypeListener with dependencies, but it will never work because the TypeListener is used to actually perform the injection.
How can I get this thing done? Is there a guicey-way?
Notes:
I'm using Guice 4.0
MyManager will be used after Guice::createInjector.
Both MyManager::registerType and MyManager::use are called exclusively before Guice::createInjector returns.
MyDependency is present to show that MyManager cannot be instanciated with new. I will also be used after Guice::createInjector has returned.
I created the following SSCCE to showcase my issue:
import com.google.inject.*;
import com.google.inject.matcher.*;
import com.google.inject.spi.*;
public class MyClass {
public static void main(String[] args) {
Guice.createInjector(new MyModule());
}
static class MyModule extends AbstractModule {
#Override protected void configure() {
TypeListener listener = new MyTypeListener();
requestInjection(listener);
bindListener(Matchers.any(), listener);
}
}
static class MyTypeListener implements TypeListener {
#Inject MyManager manager;
#Override public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<?> rawType = type.getRawType();
manager.registerType(rawType);
encounter.register(new InjectionListener<I>() {
#Override public void afterInjection(I injectee) {
manager.use(rawType, injectee);
}
});
}
}
#Singleton static class MyManager {
#Inject MyManager(MyDependency dependency) { }
void registerType(Class<?> type) { }
void use(Class<?> type, Object injectee) { }
}
static class MyDependency { }
}
I think at least some of the time (in tests or code analysis) type listeners have no cohesion to the types they are listening to, so there's no reason to have one injector. You'd use one injector to create the listener and one injector to create the code to be tested/analyzed.
If you really want one injector (e.g. if the types in the injector you wish to listen to and the types needed by the listener are cohesive) then your best bet is AbstractModule's getProvider() method. So, if MyTypeListener needs an instance of Foo, this is what MyModule would look like:
static class MyModule extends AbstractModule {
#Override protected void configure() {
TypeListener listener = new MyTypeListener(getProvider(Foo.class));
bindListener(Matchers.any(), listener);
}
}
If you haven't used getProvider(), be forewarned that you cannot call .get() on the provider until the injector is constructed. As long as you don't call it from the context of the listener's constructor you should be fine.

GWT google-gin field injection not working

I'm trying to get field injecting to work in google-gin, but when I call TestClass.test() the injected field is null. What am I doing wrong? According to the docs field injection should be really straight forward. Is there anything I'm missing in the ContextModule class?
public class MainEntry implements EntryPoint {
private final ContextInjector injector = GWT.create(ContextInjector.class);
#Override
public void onModuleLoad() {
injector.getAppMain();
}
}
#GinModules(ContextModule.class)
public interface ContextInjector extends Ginjector {
AppMain getAppMain();
}
public class MyLogger {
}
public class ContextModule extends AbstractGinModule {
#Override
protected void configure() {
bind(MyLogger.class).in(Singleton.class);
}
}
public class AppMain {
#Inject
AppMain(MyLogger logger) {
// logger is injected properly here
new TestClass().test();
}
}
public class TestClass {
#Inject
private MyLogger logger;
public void test() {
// logger is null here!
}
}
Your TestClass is not managed by GIN, so GIN won't inject anything in it. You have to either let GIN instantiate TestClass (e.g. change MyLogger to TestClass in your AppMain constructor, and call test() on the given instance), or ask GIN to inject an existing TestClass instance's members (add a method to your Ginjector that takes a TestClass as argument, when called, it'll inject fields and methods of the passed-in instance).

Categories