Simple usage of private modules and/or providers - java

New to Guice, so I'm looking into its expressive power. Suppose I have classes as follows:
public class Data {
#Inject
public Data(#Named("First") String first, #Named("Second") String second) { ... }
}
public class DataUser1 {
#Inject
public DataUser1(Data data) { ... }
}
public class DataUser2 {
#Inject
public DataUser2(Data data) { ... }
}
How do I create a module such that when I call injector.getInstance(DataUser1.class) I get something equivalent to new DataUser1(new Data("foo", "bar")) while having injector.getInstance(DataUser2.class) I get something equivalent to new DataUser2(new Data("foo2", "bar2"))?
Also related, how do I create a module for which I may need to get two instances of DataUser1, each of which using different Data values?

You use private modules for creating graphs of objects which are almost the same but differ in particular details.
public class DataUser1Module extends PrivateModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("First")).to("foo");
bindConstant().annotatedWith(Names.named("Second")).to("bar");
bind(Data.class);
bind(DataUser1.class);
expose(DataUser1.class);
}
}
public class DataUser2Module extends PrivateModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("First")).to("foo2");
bindConstant().annotatedWith(Names.named("Second")).to("bar2");
bind(Data.class);
bind(DataUser2.class);
expose(DataUser2.class);
}
}
Injector injector = Guice.createInjector(new DataUser1Module(), new DataUser2Module());
DataUser1 dataUser1 = injector.getInstance(DataUser1.class);
DataUser2 dataUser2 = injector.getInstance(DataUser2.class);
You do the same thing if you need two instances of DataUser1 with different Datas, but you use annotations to differentiate between them:
public class DataUser1Module1 extends PrivateModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("First")).to("foo");
bindConstant().annotatedWith(Names.named("Second")).to("bar");
bind(Data.class);
bind(DataUser1.class).annotatedWith(Names.named("1")).to(DataUser1.class);
expose(DataUser1.class).annotatedWith(Names.named("1"));
}
}
public class DataUser1Module2 extends PrivateModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("First")).to("foo2");
bindConstant().annotatedWith(Names.named("Second")).to("bar2");
bind(Data.class);
bind(DataUser1.class).annotatedWith(Names.named("2")).to(DataUser1.class);
expose(DataUser1.class).annotatedWith(Names.named("2"));
}
}
Injector injector = Guice.createInjector(new DataUser1Module1(), new DataUser1Module2());
DataUser1 dataUser11 = injector.getInstance(Key.get(DataUser1.class, Names.named("1"));
DataUser1 dataUser12 = injector.getInstance(Key.get(DataUser1.class, Names.named("2"));
This pattern is described in Guice FAQ.
See also these questions:
Binding a constructor argument based on the Annotation of the class
How do I bind Different Interfaces using Google Guice?

Related

Is there a more convinient to provide (bind to guice module) already created instances?

I use Guice in a desktop application and I want to add generic bindings for services. These services are singleton (binded) instances and are created during application startup manually. I use the IoC container only to create the GUI. I create these services manually because during start up I want to publish the progress.
Since the GUI consume these services, they must been binded to the guice GUI module.
I can't think of a way to bind them without using a class with setter and getter for each class.
Let's say I have CarService and EngineService. What I have now is:
public class GuiceServices {
public static void main(String[] args) {
ServicesModule servicesModule = new ServicesModule();
CarService carService = new CarServiceImpl();
servicesModule.setCarService(carService);
System.out.println("progress: 50%");
EngineService engineService = new EngineServiceImpl();
servicesModule.setEngineService(engineService);
System.out.println("Progress: 100%");
Injector i = Guice.createInjector(new GuiModule(), servicesModule);
i.getInstance(MainView.class).show();
}
class ServicesModule extends AbstractModule {
private CarService carService;
private EngineService engineService;
#Override
protected void configure() {
}
public void setCarService(CarService carService) {
this.carService = carService;
}
public void setEngineService(EngineService engineService) {
this.engineService = engineService;
}
#Provides
public CarService getCarService() {
return carService;
}
#Provides
public EngineService getEngineService() {
return engineService;
}
}
}
But it is kind of pain since these services are plenty.
Is there a way to avoid this?
Ideally, a map is more convenient. Something like:
public class GuiceServices {
public static void main(String[] args) {
ServicesMap servicesMap = new ServicesMap();
CarService carService = new CarServiceImpl();
servicesMap.put(CarService.class, carService);
System.out.println("progress: 50%");
EngineService engineService = new EngineServiceImpl();
servicesMap.put(EngineService.class, engineService);
System.out.println("Progress: 100%");
Injector i = Guice.createInjector(new GuiModule(), new ServicesModule(servicesMap));
i.getInstance(MainView.class).show();
}
class ServicesModule extends AbstractModule {
private ServicesMap services;
public SerrvicesModule(ServicesMap services) {
this.services = services;
}
#Override
protected void configure() {
for (Class<?> serviceType : services.keySet())
{
bind(serviceType).toInstance(services.get(serviceType));
}
}
}
}
But I cannot find a way to create-implement this "servicesMap". Because the bind method returns a generic builder. Does Guice (or Guava) provide something for cases like this?
I know that I can use Guice to create the services and publish the progress using an injection/type listener, but my business package (module) that contains all the services has no javax.inject dependency. Plus, the creation of these services is complex hence is better to make it manually. Also, publishing a GUI progress within a Guice module sounds too complex to be in a Guice module.
So, is there a way? Instead of the System.out.println in the above snippets, there is a splash screen that is created manually as well.
Just move the code that builds each service impl inside the body of the #Provides method for the corresponding service interface. You mentioned wanting these to be singletons, so you'll also want to annotate the provider methods with #Singleton.
As for the map, you could do something like that with a Multibinder, but I'd want to understand your design better before recommending that.
I actually achieved it myself.
What I did is to create a List<Consumer<Binder>> inside the module and then consme them inside configure() method.
class ServicesModule extends AbstractModule {
private List<Consumer<Binder>> consumers = new ArrayList<>();
ServicesModule() {
}
#Override
protected void configure() {
consumers.forEach(c -> c.accept(binder()));
}
<T> void putService(Class<T> clazz, T instance) {
consumers.add(t -> t.bind(clazz).toInstance(instance));
}
}
And then, during application start up I can feed the service dependencies gradually:
public static void main(String[] args) {
ServicesModule services = new ServicesModule();
CarService carService = new CarServiceImpl();
serviceModule.putService(CarService.class, carService);
publishProgress(35);
EngineService engineService = new EngineServiceImpl(carService);
serviceModule.putService(EngineService.class, engineService);
publishProgres(50);
//...
Injector i = Guice.createInjector(new GuiModule(), services);
i.getInstance(MainView.class).show();
}
Your proposed answer requires knowledge about the dependencies of the service-impl classes to be spread outside those classes. The whole idea of dependency injection is to encapsulate implementation dependencies. For example, only EngineServiceImpl should know that it depends on CarService. Encapsulation makes your code much easier to reason about and test.
class ServiceModule extends AbstractModule {
protected void configure() {
bind(CarService.class).to(CarServiceImpl.class).in(Singleton.class);
bind(EngineService.class).to(EngineServiceImpl.class).in(Singleton.class);
}
}
class CarServiceImpl implements CarService {
#Inject
CarServiceImpl() {} // Not necessary, but adds clarity
// ...
}
class EngineServiceImpl implements EngineService {
private final CarService carService;
#Inject
EngineServiceImpl(CarService carService) {
this.carService = carService;
}
// ...
}
class Main {
public static void main(String[] args) {
// I find it clearer to get the starting-point class instance from the injector
// creation chain, then operate on that instance.
MainView mainView =
Guice.createInjector(new GuiModule(), new ServiceModule())
.getInstance(MainView.class);
mainView.show();
}
}

Guice inject an object to a class constructor

I just started looking at Guice for a new project. I have something like this
the ConfigImpl class ans Config interface
interface Config{...}
class ConfigImpl implements Config {
private static final Map<> propMap;
public ConfigImpl(Map<> propMap) {
this.propMap = someProps;
}
}
Guice injection I came up with
public class MyInjector extends AbstractModule {
protected void configure() {
bind(Config.class).to(ConfigImpl.class)
}
}
and finally
public SomeClass {
Config someConfig;
Injector injector = Guice.createInjector(new MyInjector());
someConfig = injector.getInstance(Config.class);
}
Now I am very confused as I can't find a way to pass propMap into ConfigImpl class. I'd like to know the proper way of doing it in Guice. Thanks!
You should inject propMaps from your module:
public class MyInjector extends AbstractModule {
private final Map<String,String> mapProps;
public MyInjector(Map<String,String> mapProps) {
this.mapProps = mapProps;
}
protected void configure() {
bind(Config.class).to(ConfigImpl.class).in(Scope.SINGLETON); // You most than likely want this
bind(new TypeLiteral<Map<String,String>>() {}).toInstance(mapProps); // binding for the map.
}
}
And use it like this:
public class SomeClass {
void doSomething() {
Map<String,String> mapProps = ... ;
Injector injector = Guice.createInjector(new MyInjector(mapProps));
Config someConfig = injector.getInstance(Config.class);
}
}
Also, you should fix your ConfigImpl class:
class ConfigImpl implements Config {
private final Map<String,String> propMap;
#Inject // mandatory since you use a non-default constructor
public ConfigImpl(Map<String,String> propMap) { // add the generic type of the map
this.propMap = propMap;
}
}

Inject different instance for reusable component with Guice

I am new do dependency injection and I'm trying to solve the following problem with Google Guice:
In a web application I have got tabs which need to be reused multiple times but each time with different dependencies on their UI component and model. Something like the code here:
class MenuTabView
{
private MenuTab fooTab;
private MenuTab barTab;
}
class MenuTab
{
private UiComponent component;
#Inject
public MenuTab(UiComponent component)
{
this.component = component;
}
}
class UiComponent
{
private Model model;
#Inject
public UiComponent(Model model)
{
this.model = model;
}
}
class FooComponent extends UIComponent {}
class BarComponent extends UIComponent {}
class FooModel implements Model {}
class BarModel implements Model {}
How can I inject FooModel and FooComponent into fooTab
and BarModel and BarCompoment into barTab?
I've read a lot about the different techniques available in Google Guice but none of them seams to fit this problem which, to my naive eyes, should be a simple one. I've tried to give fooTab and barTab binding annotations but they will only work if I inject the tab but not the dependencies of the tab. What would be the most convenient way to solve this problem?
This sounds like the common "robot legs" problem to me ... this is covered in the FAQ and can be solved by using private modules:
class LegModule extends PrivateModule {
private final Class<? extends Annotation> annotation;
LegModule(Class<? extends Annotation> annotation) {
this.annotation = annotation;
}
#Override
protected void configure() {
bind(Leg.class).annotatedWith(annotation).to(Leg.class);
expose(Leg.class).annotatedWith(annotation);
bindFoot();
}
abstract void bindFoot();
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(
new LegModule(Left.class) {
#Override void bindFoot() {
bind(Foot.class).toInstance(new Foot("leftie"));
}
},
new LegModule(Right.class) {
#Override void bindFoot() {
bind(Foot.class).toInstance(new Foot("righty"));
}
});
}

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.

Categories