简体   繁体   中英

Retrieving an instance using a string literal with Google Guice

I have multiple modules with service interfaces binding to their corresponding types and I am able to get an instance by using

injector.getInstance(MyServiceInterface.class) 

I would like to retrieve the instance using

injector.getInstance("MyServiceInterface")

ie a string literal instead of the class type

How can I achieve this ?

To elaborate my question further - I can retrieve the Class object from the string literal using a Class.forName(literal) call and then use it to retrieve the instance with a injector.getInstance(clsInstance) .

After retrieving the instance which I receive in my base service type interface I need to use reflection to invoke the method of the service object.

so Service serv = injector.getInstance(MyCustomService.class)

Now I need to invoke myCustomMethod() present in MyCustomService through reflection since this invoker is generic and is intended to work with multiple services without being aware of their actual type.

I will also need the Method interceptors configured on the service interfaces to be invoked transparently when I invoke the method on this instance reflectively.

While I'm not certain if there's functionality for that built into Guice itself, you could try getting the relevant Class<?> object yourself.

Something along the lines of:

Class<?> myServiceInterfaceClass = Class.forName("path.to.MyServiceInterface");
injector.getInstance(myServiceInterfaceClass);

This does however require that the current Classloader can access that specific class, etc.

This can't be done within Guice... because it can't be done, period! Think about it, let's say you have two of the same class name in different packages . Which class would you instantiate?

So at the very least the String would have to have the fully qualified class name, eg instead of Integer , it would have java.lang.Integer .


However, if you know which classes you want to support in advance, you can use a MapBinder.

Tweaking their example to match your use case:

public class ServiceModule extends AbstractModule {
    protected void configure() {
        MapBinder<String, MyServiceInterface> mapbinder
                = MapBinder.newMapBinder(binder(), String.class, MyServiceInterface.class);
        mapbinder.addBinding("MyServiceInterface").to(MyServiceImpl.class);

        bind(MyServiceInterface.class).to(MyServiceImpl.class);
   }
}

Now you can inject like this:

class ServiceManager {
    @Inject
    public ServiceManager(Map<String, MyServiceInterface> services) {
        MyServiceInterface service = stacks.get("MyServiceInterface");
        // etc.
    }
}

Please note when you call inj.getInstance() you do have to know the return type of the Object you're trying to create, unless you are planning on doing:

Object foo = inj.getInstance(myString);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM