I'm new to Java and Guice, but I am searching if it is possible.
For example, if a have the interface
public interface A {
}
and multiple implementations for that, which in a Guice module would be:
#Override
protected void configure() {
bind(A.class).to(Aimpl.class);
bind(A.class).to(Bimpl.class);
}
I wanted to have something like that:
A[] implementations = injector.getInstance(A.class);
So I can use all implementations of the same interface!
You can use a MultiBinder :
In a module configuration :
#Override
protected void configure() {
Multibinder<A> aBinder = Multibinder.newSetBinder(binder(), A.class);
aBinder.addBinding().to(Aimpl.class);
aBinder.addBinding().to(Bimpl.class);
}
then, you can inject a Set of A :
public class MyConsumer {
#Inject
public MyConsumer(Set<A> instances) {
}
}
see https://github.com/google/guice/wiki/Multibindings
Related
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");
}
}
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();
}
Is there a way to provide custom binding in my own Module which will override binding from other nested PrivateModule .
More precisely:
I have a module with implementation:
void configure() {
binder().install(new PrivateModule() {
#Override
protected void configure() {
bind(IResourceSetProvider.class).to(XtextResourceSetProvider.class);
bind(XtextResourceSet.class).to(SynchronizedXtextResourceSet.class);
expose(IResourceSetProvider.class);
}
});
}
I would like to provide my custom implementation for IResourceSetProvider.class.
This is how I try to make it:
void configure(Binder binder) {
binder.bind(IResourceSetProvider.class).to(ExtXtextResourceSetProvider.class);
super.configure(binder);
}
When the IResourceSetProvider instance is injected it returns all the time XtextResourceSetProvider. Is there any way to implement my module to return ExtXtextResourceSetProvider?
Adam
Is there way to bind a method interceptor to a provider rather than an instance?
e.g. I use the code below to bind interceptors how would I bind INTERCEPTOR to a provider and then to the annotation?
bindInterceptor(
Matchers.any(), Matchers.annotatedWith(ANNOTATION.class), new INTERCEPTOR());
Guice does not allow AOP on instances not built by Guice: Guice AOP Limitations
"Instances must be created by Guice by an #Inject-annotated or no-argument constructor"
This means that instances created with a provider will not be candidates for AOP.
On the flip side, as long as your Provider is instantiated by Guice under the conditions mentioned, your Provider may be a candidate for AOP.
Here's an example that demonstrates this:
AOP Annotation:
#Retention(RetentionPolicy.RUNTIME) #Target(ElementType.METHOD)
#interface AOPExample {}
Provider:
public class ExampleProvider implements Provider<Example> {
#AOPExample
public Example get() {
System.out.println("Building...");
return new Example();
}
}
Target Example:
public class Example {
#AOPExample
public void tryMe() {
System.out.println("example working...");
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Module:
public class ExampleModule extends AbstractModule {
#Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), new LoggingAOP());
bind(Example.class).toProvider(ExampleProvider.class);
}
}
Test Code:
public class Test {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new TestModule());
ExampleProvider exampleProvider = injector.getInstance(ExampleProvider.class);
Example example = exampleProvider.get();
example.tryMe();
Example directExample = injector.getInstance(Example.class);
directExample.tryMe();
}
}
Test Output:
start
Building...
end took: 3
example working...
start
Building...
end took: 0
example working...
Notice that the "example working..." is not surrounded by the timer code. The Provider.get ("Building...") is however.
If your question is: can the interceptor (new INTERCEPTOR()) be provided through a Guice Provider, the answer is no. The closest you may get to this functionality is calling the requestInjection() in the module configure method. This will inject your Interceptor with the appropriate code. From your interceptor you may be able to use Providers to avoid any sort of overhead that is causing you slowness during startup.
Here's what I mean:
Module:
public class TestModule extends AbstractModule {
#Override
protected void configure() {
bind(String.class).toInstance("One");
bind(String.class).annotatedWith(Names.named("two")).toInstance("Two");
LoggingAOP loggingAOP = new LoggingAOP();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AOPExample.class), loggingAOP);
requestInjection(loggingAOP);
bind(Example.class).toProvider(ExampleProvider.class);
}
}
Interceptor:
public class LoggingAOP implements MethodInterceptor {
#Inject
private Provider<SomethingThatTakesALongTimeToInit> provider;
public Object invoke(MethodInvocation invocation) throws Throwable {
provider.get()...
System.out.println("start");
long start = System.currentTimeMillis();
Object value = invocation.proceed();
System.out.println("end took: " + (System.currentTimeMillis() - start));
return value;
}
}
Hope this answers your question.
The question, as I read it, is, how does one bind the interceptor type itself to a provider, rather than having to instantiate the interceptor at configuration time.
I don't think there's an easy way to do that, but one could write an interceptor that itself accepts a Provider for an implementation type. An example of this is shown in the Guice AOP documentation:
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
bindInterceptor(any(),
annotatedWith(NotOnWeekends.class),
new WeekendBlocker(getProvider(Calendar.class)));
}
}
I have some sample code which is using factories. I'd like to clean up the code by removing the factories and use Guice instead. I attempted to do this but I hit a small roadblock. I am really new to Guice, so I am hoping someone can help me out here.
Existing client code (Using factories):
public class MailClient {
public static void main(String[] args) {
MailConfig config = MailConfigFactory.get();
config.setHost("smtp.gmail.com");
Mail mail = MailFactory.get(config);
mail.send();
}
}
My attempt to refactor using Guice:
//Replaces existing factories
public class MailModule extends AbstractModule {
#Override
protected void configure() {
bind(Mail.class)
.to(MailImpl.class);
bind(MailConfig.class)
.to(MailConfigImpl.class);
}
}
public class MailImpl implements Mail {
private final MailConfig config;
#Inject
public MailImpl(MailConfig config) {
this.config = config;
}
public void send() { ... }
}
public class MailClient {
public static void main(String[] args) {
MailModule mailModule = new MailModule();
Injector injector = Guice.createInjector(mailModule);
MailConfig config = injector.getInstance(MailConfig.class);
config.setHost("smtp.gmail.com");
Mail mail = //??
mail.send();
}
}
How would I construct an instance of MailImpl using the object config in my revised MailClient? Should I be using Guice in this way?
Take a look at AssistedInject. It appears to address this problem.
2 solutions are possible:
1) bind the config as a guice object also, including its host parameter. then just inject Mail, in your main method you cna ignore the fact that mail has further dependencies.
2) mail must be configured individually for each send (recipient?). then you have no choice, but create it yourself using MailFactory.
You can do everything in MailModule as follows:
public class MailModule extends AbstractModule {
#Override
protected void configure() {
... // other bindings
}
#Provides
MailConfig getMailConfig( ... ) {
MailConfig config = new MailConfig( ... );
config.setHost("smtp.gmail.com");
config;
}
}
If you want a singleton MailConfig, add the #Singleton annotation to getMailConfig(), and Bob's your uncle.
Note that arguments to getMailConfig must be bound. When you bind commonly used types like String, be sure to add a binding annotation.