[3.0] Having the Provider provide a class with an Inject

82 views
Skip to first unread message

Igmar Palsenberg

unread,
Jan 29, 2015, 2:10:40 AM1/29/15
to google...@googlegroups.com
Hi,

I'm using a Provider to dynamically provide a certain class. The short(ed) code : 


public class TemplateConfigurationModule extends AbstractModule {
    
     void configure() {
              bind(TemplateResolver.class).toProvider(TemplateResolverProvider.class).in(Singleton.class);
     }
}

public class TemplateResolverProvider implements Provider<TemplateResolver> {
@Override
public TemplateResolver get() {
String templateResolverClass = .......; /* some logic */
                // FIXME : Wrong. Use the DI
Class<? extends TemplateResolver> templateResolver = AppClassloader.classloader().loadClass(templateResolverClass).asSubclass(TemplateResolver.class);
             return templateResolver.getDeclaredConstructor(TemplateRendererConfig.class).newInstance(templateRendererConfig);
}
}

public interface TemplateResolver() {
     .. Some stuff
}


public class MockTemplateResolver implements TemplateResolver {
      @Inject
      SomeObject obj;
}

So, the TemplateResolverProvider resolved a TemplateResolver class, which then at the end wants to provide a MockTemplateResolver. I've tried two things : 

1) Use the normal classloader : In that case, no @Inject gets fullfilled. Obviously.
2) Use Guice to give me a TemplateResolver class

The latter also fails : I want it to construct the object and do the injections, but it uses the Provider. Also logica.
Then I'm kinda lost : Is there a way to solve this ? For now, I've move the @Inject of SomeObject to the Provider, but that doesn't feel right.

Any advise ? 


Regards,


Igmar

Stephan Classen

unread,
Jan 29, 2015, 6:38:47 AM1/29/15
to google...@googlegroups.com
Hi

Will this configurable provider return the same concrete type of object during the whole live time of a running program?
Or will the returned type change during runtime?

Because if all you want to achieve is to be able to have mocks during unit test and real implementations during runtime then there are other ways to do this.
There are also possibilities to change the bindings at the time the injector is constructed if you would need different types depending on some environment.

The really tricky part is when you need to change the returned type during runtime.
--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-guice/6687a71a-5a3d-4e6c-87ed-170659d5c2d4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Olivier Grégoire

unread,
Jan 29, 2015, 8:07:50 AM1/29/15
to google...@googlegroups.com
Hello,

You should use the following Provider:

public class TemplateResolverProvider implements Provider<TemplateResolver> {
   
    @Inject Injector injector;

   
    @Override
    public TemplateResolver get() {
        String templateResolverClass = .......; /* some logic */
        // FIXME : Wrong. Use the DI
        Class<? extends TemplateResolver> templateResolver = AppClassloader.classloader().loadClass(templateResolverClass).asSubclass(TemplateResolver.class);
        TemplateResolver instance = templateResolver.getDeclaredConstructor(TemplateRendererConfig.class).newInstance(templateRendererConfig);
        injector.injectMembers(instance);
        return instance;
    }
}

I hope this helps.


Regards,
Olivier


For more options, visit https://groups.google.com/d/optout.



--
Olivier Grégoire

Igmar Palsenberg

unread,
Jan 29, 2015, 10:31:02 AM1/29/15
to google...@googlegroups.com
Hi,


    @Override
    public TemplateResolver get() {
        String templateResolverClass = .......; /* some logic */
        // FIXME : Wrong. Use the DI
        Class<? extends TemplateResolver> templateResolver = AppClassloader.classloader().loadClass(templateResolverClass).asSubclass(TemplateResolver.class);
        TemplateResolver instance = templateResolver.getDeclaredConstructor(TemplateRendererConfig.class).newInstance(templateRendererConfig);
        injector.injectMembers(instance);
        return instance;
    }
}


I'll give this a try. Just what I need. I didn't know that I could inject when the object was already created.


Regards,

Igmar 

Igmar Palsenberg

unread,
Jan 29, 2015, 10:44:20 AM1/29/15
to google...@googlegroups.com
Work perfectly. Thanks !!


Igmar

Stephan Classen

unread,
Jan 29, 2015, 11:09:15 AM1/29/15
to google...@googlegroups.com
Even tough you have a working solution now. It is not pretty and from my perspective hard to understand what is actually happening.
So I am still wondering if you need to change the returned type during runtime or if the returned type gets fixed during startup of the application.
Because if it is fixed during startup there are cleaner ways of achieving what you want.
--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.

Igmar Palsenberg

unread,
Jan 30, 2015, 5:17:12 PM1/30/15
to google...@googlegroups.com

Even tough you have a working solution now. It is not pretty and from my perspective hard to understand what is actually happening.
So I am still wondering if you need to change the returned type during runtime or if the returned type gets fixed during startup of the application.
Because if it is fixed during startup there are cleaner ways of achieving what you want.

It get's fixed during application startup. I prefer a solution that gives me a constructed object from the injector, but the current solution is also acceptable, yet not perfect : Some custom annotations of this framework stop to functioning. The stacktrace makes no sense (a known issue with Guice 3 and Java 8).

If you have a suggestion : Please let me know.



Regards,


Igmar

Stephan Classen

unread,
Feb 1, 2015, 3:20:45 PM2/1/15
to google...@googlegroups.com
There are several ways to do it.

You can simply introduce logic in you modules which allows to configure the bindings at startup time.
This is the simplest way but if the logic gets complexer it will also be hard to understand.
You can group bindings which belong together into modules and then include/exclude entire modules instead of single bindings.

Another possibility is to use the override feature of guice.
This allows you to define default bindings and then selectively replace them with another binding.
The syntax is as follows:

Modules.override(defaultBindingModule).with(specialBindingModule);

In your first post you mentioned mocks. If you want to use guice within unit tests then there are frameworks which ease the burden of the boiler plate code.
For example jukito will create a new injector for every test class. It also allows to easily define the bindings you want and it can create bindings to mockito mocks for all missing bindings on the fly.

Hope this gets you started. If you need more hints you can always come back to this place.
--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
Reply all
Reply to author
Forward
0 new messages