Creating guice injector of another module installed inside current module - java

Have an interface that needs many implementations to be bound to it.
Going for the following design because of many constraints (May not seem good, please ignore the design).
Is it possible to create an injector for another module installed in current module while still running the configure() method for the current module.?
public class CurrentModule extends AbstractModule{
#Override
protected void configure() {
install(new OtherModule());
final someInterface getInstance = methodToGetInstance();
bind(SomeInterface.class).to(getInstance);
}
public SomeInterface methodToGetInstance() {
Injector injector = Guice.createInjector(new OtherModule());
return new ClassImplementingSomeInterface(injector.getInstance(dependency));
}
}

Yes, what you ask is possible with provider methods. This is how you should do it:
class CurrentModule extends AbstractModule {
#Override protected void configure() {
install(new OtherModule());
// Optional, but it's good to write it if the dependency becomes missing from OtherModule.
requireBinding(DependencyFromOtherModule.class);
}
#Singleton
#Provides SomeInterface createSomeInterface(DependencyFromOtherModule dependency) {
return new ClassImplementingSomeInterface(dependency);
}
}

Related

Java binding instance using other instance using Guice

there is a configuration file that I want to bind using Guice but the problem is I get that file using my manager class and I don't have an instance of it. To make clear, I explain on code:
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ConfigManager.class).to(SimpleConfigManager.class).asEagerSingleton(); // My manager
bind(PropertiesConfiguration.class).annotatedWith(Names.named("versionConfig")).toInstance(configManager.getResourceConfig("version.properties"));
// ^ I need an instance of SimpleConfigManager here
}
}
So, how can I create/get an instance without using the "new" keyword?
You can use something called ProvidesMethod.
public class GuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(ConfigManager.class).to(SimpleConfigManager.class).asEagerSingleton();
}
#Provides
#Singleton
#Named("versionConfig")
public PropertiesConfiguration providePropertiesConfiguration(ConfigManager configManager) {
return configManager.getResourceConfig("version.properties");
}
}

Java Guice Named Bindings with Objects provided from other modules

Heres my current setup
Class file
public class ToyAdapter {
private final ToyClient toyClient;
private final Retryer retryer;
#Inject
public APIAdapter(final ToyClient toyClient,
#Named("toyRetryer") final Retryer retryer) {
this.toyClient = toyClient;
this.retryer = retryer;
}
Guice file
I have several guice modules, but this one pertains to the above class
public class ToyModule extends AbstractModule {
#Override
protected void configure() {
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
#Provides
#Singleton
public ToyClient getToyClient(...){
...
}
private Retryer getToyRetryer() {#Takes no arguments
return RetryerBuilder...build();
}
}
So far this works great! However, now my retryer requires a LogPublisher object provided in another module.
I'm trying
public class ToyModule extends AbstractModule {
LogPublisher logPublisher;
#Override
protected void configure() {
requestInjection(logPublisher);
bind(ToyAdapter.class).in(Singleton.class);
bind(Retryer.class).annotatedWith(Names.named("toyRetryer")).toInstance(getToyRetryer());
}
private Retryer getToyRetryer() {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}
}
LogPublisher is provided in another guice module which has alot of other objects that depend on LogPublisher so I'd rather not just merge everything into one giant guice module.
#Provides
#Singleton
public LogPublisher getLogPublisher() {...}
Is this the proper way to do this? I'm getting Java findBugs errors saying unwritten field so I'm thinking I'm doing it wrong.
Declare your Retryer with help of #Provides/#Named annotations.
#Provides
#Singleton
#Named("toyRetryer")
public Retryer getToyRetryer(LogPublisher logPublisher) {
return RetryerBuilder.withLogPublisher(logPublisher).build();
}

Guice: Injecting a Module and then installing it

Here's something weird. Suppose you have a module like this:
public class ParentModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("key")).to("key");
}
}
Then we also have something like this:
public class DependentModule extends AbstractModule {
private final String key;
#Inject public DependentModule(#Named("key") String key) { this.key = key; }
#Override
public void configure() {
// Configure bindings that make use of key...
}
}
Injector parent = Guice.createInjector(new ParentModule());
Injector child = parent.createChildInjector(parent.getInstance(DependentModule.class));
// Now just ignore parent and work with child exclusively
This seems extremely cumbersome, but possibly necessary and useful in certain situations (if the key is a more complex datatype, for instance). Regardless, is there a way to restructure this code such that ParentModule binds the key, creates the DependentModule using the key, and install the created DependentModule? That is, such that the consumer can simply use a single injector instead of having to do this two-injector trick?
It isn't possible to inject something and then install it. Injection only happens after all your configure() methods have run, by which point it's too late. But you can do this:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("key")).to("key");
}
#Provides
Dependency provideDependency(#Named("key") String key) {
// Use key here
}
}

Override jersey resource with guice

I'm looking for a method to override jersey resources bounded with guice in GuiceServletContextListener. My code, which I'm trying to get working:
//Define Jersey resource interface
#Path("/books/{key}")
public interface BookDocument {
public BookDAO getDao();
public void setDao(BookDAO dao);
}
//Define default implementation
public class BookImpl implements Book {
#Override
public BookDAO getDao() {
return dao;
}
#Inject
#Override
public void setDao(BookDAO dao) {
this.dao = dao;
}
}
//User wants to inject his implementation, so he define it
public class BookUserImpl implements Book {
#Override
public BookDAO getDao() {
return dao;
}
#Inject
#Override
public void setDao(BookDAO dao) {
this.dao = dao;
}
}
//Inject default implementation of resource
public class ApplicationResourcesModule extends AbstractModule
{
#Override
protected void configure()
{
bind(Book).to(BookImpl);
}
}
//But user wants to inject his implementation, so he bind it in users AbstractModule
public class ApplicationResourcesModuleUser extends AbstractModule
{
#Override
protected void configure()
{
bind(Book).to(BookUserImpl);
}
}
//Bind all resources
public class JerseyGuiceConfig extends GuiceServletContextListener
{
#Override
protected Injector getInjector()
{
//Override default binding by user bindings.
return Guice.createInjector(Modules.override(new ApplicationResourcesModule()).with(new ApplicationResourcesModuleUser()), new JerseyServletModule());
}
}
But unfortunately this doesn't work, while I can't bind jersey resources in guice like interface to implementation, only bind(BookImpl.class) work's. But such binding is impossible to overwrite. If I try to override bind(BookImpl.class) with bind(BookUserImpl.class) I get an error Conflicting URI templates. The URI template /books/{key} for root resource class. while #Path should be unique. So is there any solution for my use case?
i just wan't to warn you Modules.override does not work on Guice.createInjector(Stage.PRODUCTION,...) so you should use it carefully only for Development. You should create two context listeners and somehow (trough maven profiles lets say) setup the web.xml with proper implementation.
Better to use:
//Inject default implementation of resource
public class MainModule extends AbstractModule
{
#Override
protected void configure()
{
if(currentStage().equals(Stage.PRODUCTION) {
install(new ApplicationResourcesModuleUser());
} else {
install(new ApplicationResourcesModule());
}
}
}
//Bind all resources
public class JerseyGuiceConfigPROD extends GuiceServletContextListener
{
#Override
protected Injector getInjector()
{
//Override default binding by user bindings.
return Guice.createInjector(Stage.PRODUCTION, new MainModule(), new JerseyServletModule());
}
}
public class JerseyGuiceConfigDEV extends GuiceServletContextListener
{
#Override
protected Injector getInjector()
{
//Override default binding by user bindings.
return Guice.createInjector(Stage.DEVELOPMENT, new MainModule(), new JerseyServletModule());
}
}
You can use #ImplementedBy annotation to your interface to say the default implementation should be. So, you don't have to bind it explicitly and you, if you bind it, it will override the annotation binding.
#Path("/books/{key}")
#ImplementedBy(BookImpl.class)
public interface Book {
public BookDAO getDao();
#Inject //it is enough to put the injection here, i think
public void setDao(BookDAO dao);
}
I think this problem is not related to Book and Book implementations binding, but to a binding/registering of the servlets to the Jersey container. Could you paste whole stacktrace, the guice stacktraces are verbose and very helpful.

Injecting singleton in guice module

I have written some modules with guice. These are working great.
I have also some singletons or a logger I need in my modules which I want to inject into these modules.
For example I have my JpaModule where I need my Configuration.
ConfigurationModule:
#Singleton
public class ConfigurationModule extends AbstractModule {
#Override
protected void configure() {
bind(Configuration.class).toProvider(ConfigurationProvider.class).in(Singleton.class);
}
}
JpaModule:
public class JpaDaoModule extends AbstractModule {
#Inject
Configuration config;
#Override
protected void configure() {
// ... Read config and do something
}
}
Call to Guice:
Guice.createInjector(new ConfigurationModule(), new JpaDaoModule());
How can I accomplish this? Or how can I provide the configuration to the JpaModule the guicy way?
/Kind regards
Christian
This is not possible. In the configure() method you set up your bindings. You cannot expect them to be available already. Also, modules are not eligible for injection per se. You can, however, get access to Guice-managed instances in providers or #Provides methods.
#Provides
#Named("myConfigItem")
String provideSomeConfigItem(Configuration config) {
return config.get("myConfigItem");
}

Categories

Resources