Is there a way to declare default binding in Guice 3.0 ?
Here is an example of what I expected :
//Constructor for Class Impl1
#Inject
public Impl1 (#One IMyOwn own)
{
...
}
//Constructor for Class Impl2
#Inject
public Impl2 (#Two IMyOwn own)
{
...
}
//Declare a default binding
bind(IMyOwn.class).to(DefaultMyOwn.class);
//Then, if I want to bind a custom implementation for #Two
bind(IMyOwn.class).annotatedWith(Two.class).to(TwoMyOwn.class);
Actually, this example can't works because I must declare a binding for all annotation (#One, #Two).
Are there solutions to do that with Guice ?
Thanks.
Use the #Named binding.
From Guice Reference on Github:
Guice comes with a built-in binding annotation #Named that uses a string:
public class RealBillingService implements BillingService {
#Inject
public RealBillingService(#Named("Checkout") CreditCardProcessor processor) {
...
}
To bind a specific name, use Names.named() to create an instance to pass to annotatedWith:
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
So in your case,
//Constructor for Class Impl1
#Inject
public Impl1 (#Named("One") IMyOwn own)
{
...
}
//Constructor for Class Impl2
#Inject
public Impl2 (#Named("Two") IMyOwn own)
{
...
}
and your module will look like:
public class MyOwnModule extends AbstractModule {
#Override
protected void configure() {
bind(IMyOwn.class)
.annotatedWith(Names.named("One"))
.to(DefaultMyOwn.class);
bind(IMyOwn.class)
.annotatedWith(Names.named("Two"))
.to(TwoMyOwn.class);
}
}
With Guice 4.X there is Optional Binder.
public class FrameworkModule extends AbstractModule {
protected void configure() {
OptionalBinder.newOptionalBinder(binder(), Renamer.class);
}
}
public class FrameworkModule extends AbstractModule {
protected void configure() {
OptionalBinder.newOptionalBinder(
binder(),
Key.get(String.class, LookupUrl.class))
.setDefault().toInstance(DEFAULT_LOOKUP_URL);
}
}
In Guice 3.0 you may be able to exploit the automatic binding of the default constructor.
Use a single #Inject or public no-arguments constructor.
But this has constraints, as your default constructor needs to be of the same concrete class so derivation may become cumbersome.
Guice tries to check as much of your configuration (aka. Binding) as possible. This also means, that Guice cannot tell whether a missing binding for #One is an error or should map to some default case.
If you are interested in the details, lookup the BindingResolution sequence in Guice. Since step 4 and step 6 deal with binding annotation and step 6 explicitly forbids default, I think you are out of luck.
.6. If the dependency has a binding annotation, give up. Guice will not create default bindings for annotated dependencies.
So the best you can do is to provide Guice with a hint, that #One should map to the default like this:
bind(IMyOwn.class).annotatedWith(One.class).to(IMyOwn.class);
So you do not need to state the concrete default class DefaultMyOwn multiple times.
Related
Hallo i would like to find a way to elect programmatically a Candidate between different implementation present on the bean factory, at Spring Container Level.
With Profiles i can achieve that simply like this
I Have the following Profiles "CH" and "IT" and i want that if a Bean Profiled with IT is there, then will fallback to default.
Given those classes:
The Default Implementation
#Component
public class DefaultMapper {
public void doSomething() {
System.out.println("Map Default");
}
}
The Swiss Implementation
#Component
#Profile("CH")
public class SwissMapper extends DefaultMapper {
#Override
public void doSomething() {
System.out.println("do something swiss");
}
}
The Italian Implementation:
#Component
#Profile("IT")
public class ItalianMapper extends DefaultMapper {
#Override
public void doSomething() {
System.out.println("do pasta");
}
}
Now if i run it with #ActiveProfiles("IT") it throws a NoUniqueBeanDefinitionException, which is fair enough, since the Default is not profiled, and it will be registered without any further attention by the container.
Some Consideration:
if i add #Profile("default") to DefaultMapper this will work until i have another default bean has a subclass profiled ONLY with CH.
Default Implementation of another Bean:
#Component
#Profile("default")
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
Then the Swiss implementation (No italian is available, or better said the default fits for italian):
#Component
#Profile("CH")
public class SwissParser extends DefaultParser {
#Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
}
Now if i run it with #ActiveProfiles("IT") it throws a No BeanDefinitionException, which is fair enough, but not that fair, since the "default" is not chained as ActiveProfiles and for IT i have no implementation. the CH profile here will work since has a profiled implementation for each default class.
Said That
I would like a better way to cover this scenario without:
- Having to define on the Default Classes such #Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"} , or #Profile("!CH") where i exclude those profiles which have a specialization.
- #Primary i think is not a soultion, because on the DefaultMapper i have to Specialization which will be marked as #Primary and the container doesn't like it at all ;)
Then
I would like to solve this where i can decide for ALL the injected Classes, when the resolution of the Beans is ambigous then i would like to programmatically decide (in container) which implementation i would like to pick. I think an Annotation likewise to #Profile , i.E #Candidate("CH") will suit compared to a value set in application.properties in a i.E nationality.cantidate=CH. Something like:
public class MyExtension extends UnknowSpringType {
#Override
Object resolveAmbigousDependency(final Context ctx, final Resolution resolution) {
final List<Class> clazzes = resolution.getResolvedClasses();
for (final Class clazz : clazzes) {
if (clazz.isAnnotationPresent(Candidate.class) && clazz.getAnnotation(Candidate.class).getVaue().equals(candidateApplicationPropertyValue)) {
return clazz;
}
return getDefaultImplementation(clazzes);
}
}
I've done in the past Something similar with CDI SPI extension wich is elegant, and also i could cover this in another way with #Specializes from CDI, but i cannot find the same easy way on Spring (i don't have so much experience on it), BeanFactory? BeanFactoryPostProcessor ?
Help ?
You can mark all your specific Parsers as #Primary this will make sure Spring autowires this one instead of the default one which is not marked as #Primary. When no specific Parsers exist for the chosen profile it will fall back to the non #Primary default component.
See: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html
#Component
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
#Component
#Primary
#Profile("CH")
public class SwissParser extends DefaultParser {
#Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
You can activate multiple profiles, CH and IT and your implementation will fail.
It is a internationalization problem.
I have an interface which has both a default implementation and a client-specific implementation.
Interface:
#ImplementedBy(CoreServiceImpl.class)
interface CoreService {
// Methods
}
Default implementation:
class CoreServiceImpl implements CoreService {
// Methods
}
In my specific Guice Module, I use a different implementation:
Module:
...
bind(CoreService.class).to(ClientSpecificServiceImpl.class);
...
Implementation:
class ClientSpecificServiceImpl implements CoreService {
// Methods
}
However, within this class I require an instance of the default implementation.
How can I tell Guice to "inject an instance of the default implementation of this interface"?
I could reference the current default implementation by type name, e.g.
class ClientSpecificServiceImpl implements CoreService {
private final CoreServiceImpl coreServiceImpl;
#Inject
ClientSpecificServiceImpl(CoreServiceImpl coreServiceImpl) {
this.coreServiceImpl = coreServiceImpl;
}
}
.. but if the default implementation (the one inside #ImplementedBy) changed, I wouldn't pick up the change. Should this be done via reflection? Is there a better way?
Use an injection annotation, if you want different implementations to be injected in different places. In other words, for the one client:
class ClientSpecificApp {
private final CoreService coreService;
#Inject
ClientSpecificServiceImpl(#Named("clientName") CoreService coreService) {
this.coreService = coreService;
}
}
For everyone else:
class DefaultApp {
private final CoreService coreService;
#Inject
DefaultApp(CoreService coreService) {
this.coreService = coreService;
}
}
Then, bind that that annotation in your Guice module:
protected void configure() {
bind(CoreService.class).annotatedWith(Names.named("clientName") CoreService);
}
Then, all you have to do is change the binding in the module for the client specific version if it changes.
Further reading: Binding Annotations
I am currently trying to integrate Dagger 2 into an Android application. My project setup is as follows:
library
app (depends on library)
In my library project I defined a class that I'll later inject into other classes that need it (Activities and regular classes) in the library as well as the app project.
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Now - for instance in my Fragments or Activities or regular classes I'd inject the above Singleton as follows:
public class SomeClass{
#Inject
MyManager myManager;
}
Or so I thought, because in practice myManager is always null. And apparently it's constructor is never called either, so I guess I must be missing something configuration-wise? Or maybe I misunderstood the documentation and it's not meant to work this way at all? The purpose of MyManager class is to be an application-wide accessible component-accumulating entity - that's why I went for the #Singleton.
UPDATE
To avoid confusion: I mentioned my having components somewhere in a comment I think - this refers to components in the sense of "component based design" and has nothing to do with dagger. The dagger-based code I have is all listed above - there is nothing else related to dagger in my code.
When I started adding #Component I had some compiler issues, because my dagger2 was not setup properly - check out this really helpful thread on how to setup dagger2 correctly: https://stackoverflow.com/a/29943394/1041533
UPDATE 2
Here is my updated code, based on G. Lombard's suggestions - I changed the code as follows - the original Singleton is in the library project:
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Also in the library project is the bootstrap class:
#Singleton
#Component
public interface Bootstrap {
void initialize(Activity activity);
}
Then I use the above Bootstrap class in my activity (in my concrete app, NOT in the library project! I do however also have Classes/Activities in the library that'll access Bootstrap to inject MyManager):
public class MyActivity extends Activity{
#Inject
MyManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//DONT DO THIS !!! AS EXPLAINED BY EpicPandaForce
DaggerBootstrap.create().initialize(this);
}
}
But even after this line:
DaggerBootstrap.create().initialize(this);
the manager instance is still null, i.e. not injected.
I just found this: https://stackoverflow.com/a/29326023/1041533
Which if I don't misread, implies I need to specify every single class in the Bootstrap class that will use #Inject to have stuff injected. Sadly - this is not an option, as I have more than 40 classes and activities for which I'd have to do that.
Meaning my Bootstrap interface apparently would have to look something like this:
#Singleton
#Component
public interface Bootstrap {
void initialize(ActivityA activity);
void initialize(ActivityB activity);
void initialize(ActivityC activity);
void initialize(ActivityD activity);
void initialize(ActivityE activity);
void initialize(ActivityF activity);
//and so on and so forth...
}
If the above is true, that would not be worth it for my use case. Plus: Seems there is no compile-time check, if I forgot to specify one of my 40+ classes here? It just wont work - i.e. crash the app at runtime.
You're making a mistake in that you are using
DaggerBootstrap.create().initialize(this);
in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class
public class CustomApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Bootstrap.INSTANCE.setup();
}
}
#Component
#Singleton
public interface _Bootstrap {
void initialize(ActivityA activityA);
//void initiali...
}
public enum Bootstrap {
INSTANCE;
private _Bootstrap bootstrap;
void setup() {
bootstrap = Dagger_Bootstrap.create();
}
public _Bootstrap getBootstrap() {
return bootstrap;
}
}
Then you could call it as
Bootstrap.INSTANCE.getBootstrap().initialize(this);
This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:
Injector.INSTANCE.getApplicationComponent().inject(this);
But that's just my typical setup. Names don't really matter.
EDIT: To your last question, you can solve this by subscoping and component dependencies.
Your library project should be able to see only the library classes, correct? In that case, all you do is
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface LibraryScope {
}
#Component(modules={LibraryModule.class})
#LibraryScope
public interface LibraryComponent {
LibraryClass libraryClass(); //provision method for `MyManager`
}
#Module
public class LibraryModule {
#LibraryScope
#Provides
public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
return new LibraryClass(); //this is instantiation of `MyManager`
}
}
public enum LibraryBootstrap {
INSTANCE;
private LibraryComponent libraryComponent;
static {
INSTANCE.libraryComponent = DaggerLibraryComponent.create();
}
public LibraryComponent getLibraryComponent() {
return libraryComponent;
}
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
#ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
AdditionalAppClass additionalAppClass();
void inject(InjectableAppClass1 injectableAppClass1);
void inject(InjectableAppClass2 injectableAppClass2);
void inject(InjectableAppClass3 injectableAppClass3);
}
#Module
public class AdditionalAppModule {
#ApplicationScope
#Provides
public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
return new AdditionalAppClass();
}
}
public enum ApplicationBootstrap {
INSTANCE;
private ApplicationComponent applicationComponent;
void setup() {
this.applicationComponent = DaggerApplicationComponent.builder()
.libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
Then
#Inject
LibraryClass libraryClass; //MyManager myManager;
...
ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);
It's hard to say what your problem was, since you didn't show what your Component looks like and whether you have multiple components etc.
Assuming this logical structure:
/app
MainComponent
SomeClass // where MyManager is to be injected
MainActivity // where SomeClass is to be injected
/library
LibraryComponent
MyManager // Singleton
Then your classes as listed would inject correctly with the following configuration:
#Singleton
#Component
public interface LibraryComponent {
MyManager getMyManager();
}
and the app-level component to inject dependencies into the activity:
#ActivityScope
#Component(dependencies = LibraryComponent.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
Note that MainComponent depends on LibraryComponent, but because the latter has singleton scope, you need to define a scope for the other one too, which I was I used the "activity scope" here. (Or you could also just make the MainComponent a singleton and get rid of the LibraryComponent completely if that suits your needs.)
Finally it's all injected into the activity like this:
#Inject
SomeClass someClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.libraryComponent(DaggerLibraryComponent.create())
.build()
.inject(this);
someClass.doSomething();
}
I've put a working sample here on GitHub
Update 1:
If I understand your setup correctly, you've so far only used the #Singleton and #Inject annotations on the two classes listed (MyManager and SomeClass), and there is no other Dagger-related code in your project.
In that case, the reason your MyManager isn't getting injected, is because Dagger doesn't know how to provide/instantiate the dependencies. This is where the "components" come in that I mentioned above. Without any Dagger 2 components (interface or abstract class annotated with #Component), your dependencies won't get injected automatically.
I don't know if you have experience with Dependency Injection concepts, but assuming you don't, I'll step through the minimum basics you'll need to understand to get your MyManager injected into SomeClass:
First: when you use DI, you need to understand the difference between "newables" and "injectables". This blogpost by Misko Hevery explains the details.
This means, you can't new up your SomeClass. This won't work:
mSomeClass = new SomeClass();
Because if you did that (say in an activity or fragment), Dagger will have no idea that you expected a dependency to get injected into SomeClass and it has no opportunity to inject anything.
In order for its dependencies to get injected, you have to instantiate (or inject) SomeClass itself through Dagger too.
In other words, say in your Activity where SomeClass is used, you'll need:
#Inject
SomeClass mSomeClass;
Next, you need a Dagger component to perform the actual injection. To create a component, you create an interface with a method that takes your root object (say MainActivity) as argument, e.g.:
#Singleton
#Component
public interface Bootstrap {
void initialize(MainActivity activity);
}
Now when you build your project, Dagger 2 generates a class called DaggerBootstrap that implements this interface. You use this generated class to perform the injection, say in your activity's onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBootstrap.create().initialize(this);
mSomeClass.doSomething();
}
I believe this generated component is the key part you're missing. Full code for above here.
Some useful Dagger 2 resources:
the official Dagger 2 guide
reddit page with lots of links
Update 2:
Seems like the final missing piece of the puzzle was that your component provided an inject method for the Activity base class, but not for your actual concrete activity.
Unfortunately Dagger 2 requires an inject method for each activity or other class you want to inject into.
As you mentioned, this will be annoying when you have many different activities in your app. There some possible workarounds for this, search for "dagger 2 inject base class", for example this suggestion by #EpicPandaForce: Dagger 2 base class injections
Also note, as pointed out by #EpicPandaForce in the comments, that in my simplistic example I called DaggerLibraryComponent.create() every time which is probably not what you want, since that component is supposed to provide your singletons, so you're probably better off getting the existing instance from somewhere else such as from your Application instance.
I would like to use goolge/guice inject a value based on a class i provide with the annotation.
AutoConfig annotation
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.PARAMETER, ElementType.FIELD })
public #interface AutoConfig {
// default null not possible
Class<? extends Provider<? extends ConfigLoader<?>>> provider() default XMLAutoConfigProvider.class;
}
This is my annotation which allows configuring the type of config, that should be used for the annotated fields.
Usecase:
#AutoConfig()
ConfigLoader<?> defaultConfig;
#AutoConfig(provider = JsonConfigProvider)
ConfigLoader<?> jsonConfig;
I want to have two configs, one default/xml one and a json one. They will probably never occur in the same class at the same time. But i don't know when the one or the other is used. I used the approach with a class because they are provided by some dependencies/libs and this annotation will be used for some (plugable) submodules.
MyGuiceModule
public class MyGuiceModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<ConfigLoader<?>>() {})
.annotatedWith(AutoConfig.class)
.toProvider(autoConfig.provider());
}
}
This the critical part, i just cannot imagine how to implement it.
So basically i just want to use the provider class specified in the annotation.
Its not necessary to use the provider class here too. Because autoConfig.provider().newInstance() is basically all i need. (I need to use a setter on the new instance but thats all i want to do at this place)
To sum it up all i really want to do is push the annotation (or its values to the provider) either using the get(AutoConfig autoConfig) or in the constructor.
Currently i only use the constructor to inject the configFile value i want to set on the newly generated config instance.
If you know that #AutoConfig(provider = JsonConfigProvider) ConfigLoader<?> jsonConfig is going to return you exactly the results of jsonConfigProvider.get(), and JsonConfigProvider obviously has a public parameterless constructor for newInstance to work, why wouldn't you just ask for a JsonConfigProvider in the first place?
Fundamentally Guice is just a Map<Key, Provider> with fancy wrapping. The bad news is that this makes variable bindings like "bind Foo<T> for all T" impossible to express concisely, and that includes your "bind #Annotation(T) Foo for all T". The good news is that you still have two options.
Bind each provider separately
Though you can't inspect annotations during provision (or tell Guice to do so for you), Guice will compare annotations using their equals methods if you bind an annotation instance rather than an annotation class (the way you would with Names.named("some-name")). This means that you can bind a ConfigLoader<?> with each expected annotation in a Module. Of course, this also means you'll have to have a list of possible ConfigLoader Providers available at configuration time, but they have to be compile-time constants anyway if you're using them as annotation parameters.
This solution works with constructor injection as well, but for fields you'll need both #Inject and #AutoConfig(...), and AutoConfig will need to keep its #BindingAnnotation meta-annotation.
To do this, you're going to have to write an implementation of your annotation, the way Guice does with NamedImpl. Note that the implementations of equals and hashCode must match the ones Java provides in java.lang.Annotation. Then it's just a matter of (redundantly) binding like this:
for(Class<ConfigLoader<?>> clazz : loaders) {
bind(ConfigLoader.class).annotatedWith(new AutoConfigImpl(clazz))
.toProvider(clazz);
}
The definition of equals is up to you, which means you can (and should) bind #AutoConfig(ConfigEnum.JSON) and keep the Guice bindings in your modules rather than specifying your requested implementation all over your codebase.
Use custom injections
You can also use custom injections to search your injected types for custom annotations like #AutoConfig. At this point, you'd be using Guice as a platform to interpret #AutoConfig instead of #Inject, which means that constructor injection won't work but that you can control your injection based on the injected instance, field name, field annotation, annotation parameters, or any combination thereof. If you choose this style, you can drop #BindingAnnotation from AutoConfig.
Use the example in the wiki article linked above as your template, but at minimum you'll need to:
Use bindListener on Binder or AbstractModule to match types that need this custom injection.
In the TypeListener you bind, search injected types for #AutoConfig-annotated fields, and if they have any matching methods then bind those matching methods to a MembersInjector or InjectionListener. You'll probably want to tease the class literal out of the annotation instance here, and pass in the Field and Class as constructor arguments to the MembersInjector/InjectionListener.
In the MembersInjector or InjectionListener you write, instantiate the provider and set the field to the instance the provider provides.
This is a very powerful feature, which would futher allow you to--for instance--automatically provide the configuration based on which instance you're injecting into or based on the name of the field. However, use it carefully and document it heavily, because it may be counter-intuitive to your coworkers that Guice is providing for an annotation other than #Inject. Also bear in mind that this won't work for constructor injection, so refactoring from field injection to constructor injection will cause Guice to complain that it's missing a required binding to instantiate the class.
I had a similar problem. I wanted to use a custom annotation that receives a enum param to choose the implementation. After a lot of research, debug and testing, I came to the following solution:
//enum to define authentication types
public enum AuthType {
Ldap, Saml
}
//custom annotation to be used in injection
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
#BindingAnnotation
public #interface Auth {
AuthType value();
}
//defintion of authenticator
public interface Authenticator {
public void doSomehting();
}
//Authenticator implementations
public class LdapAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing ldap stuff
}
}
public class SamlAuthenticator implements Authenticator {
#Override
public void doSomehting() {
// doing saml stuff
}
}
public class MyModule extends AbstractModule {
// annotate fields to bind to implementations
private #Auth(AuthType.Ldap) Authenticator ldap;
private #Auth(AuthType.Saml) Authenticator saml;
#Override
protected void configure() {
//bind the implementation to the annotation from field
bindAnnotated("ldap", LdapAuthenticator.class);
bindAnnotated("saml", SamlAuthenticator.class);
}
private void bindAnnotated(String fieldName, Class<? extends Authenticator> implementation) {
try {
//get the annotation from fields, then bind it to implementation
Annotation ann = MyModule.class.getDeclaredField(fieldName).getAnnotation(Auth.class);
bind(Authenticator.class).annotatedWith(ann).to(implementation);
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
//usage: add #Auth(<AuthType>) to the dependency
public class ClientClass {
private Authenticator authenticator;
#Inject
public ClientClass(#Auth(AuthType.Ldap) Authenticator authenticator) {
this.authenticator = authenticator;
}
}
Check the documentation of Binder
I tested the Jeff Bowman solution, but it apparently works only binding to providers
As a BindingAnnotations#binding-annotations-with-attributes states equals() and hashCode() should be properly implemented. So given that there is MyAnnotation
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
public #interface MyAnnotation {
SomeEnum value() default SomeEnum.A;
}
which is used to specify SomeInterface implementation(SomeDefault and SomeOther), SomeModule class could look like
public class SomeModule extends AbstractModule {
#Override
protected void configure() {
bind(Key.get(SomeInterface.class, createAnnotationClass(A))).to(SomeDefault.class);
// more common binding expresion
bind(SomeInterface.class).annotatedWith(createAnnotationClass(B)).to(SomeDefault.class);
}
private Annotation createAnnotationClass(SomeEnum someEnum) {
return new MyAnnotation() {
#Override
public SomeEnum value() {
return someEnum;
}
#Override
public Class<? extends Annotation> annotationType() {
return MyAnnotation.class;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyAnnotationCl myAnnoCl = (MyAnnotationCl) o;
return A == myAnnoCl.getValue();
}
#Override
public int hashCode() {
// from java annotation documentation
return (127 * "value".hashCode()) ^ value().hashCode();
}
};
}
}
Then annotation could be used as follows:
public class DoSomethingWithSomething {
private final SomeInterface someImplementation;
#Inject
public DoSomethingWithSomething(
#MyAnnotation SomeInterface someDefault
// #MyAnnotation(A) SomeInterface someDefault
// #MyAnnotation(B) SomeInterface someOther
) {
this.someImplementation = someDefault;
}
}
So far, I successfully used google guice 2. While migrating to guice 3.0, I had troubles with assisted inject factories. Assume the following code
public interface Currency {}
public class SwissFrancs implements Currency {}
public interface Payment<T extends Currency> {}
public class RealPayment implements Payment<SwissFrancs> {
#Inject
RealPayment(#Assisted Date date) {}
}
public interface PaymentFactory {
Payment<Currency> create(Date date);
}
public SwissFrancPaymentModule extends AbstractModule {
protected void configure() {
install(new FactoryModuleBuilder()
.implement(Payment.class, RealPayment.class)
.build(PaymentFactory.class));
}
}
While creating the injector, I get the following exception:
com.google.inject.CreationException: Guice creation errors:
1) Payment<Currency> is an interface, not a concrete class.
Unable to create AssistedInject factory. while locating Payment<Currency>
at PaymentFactory.create(PaymentFactory.java:1)
With the assisted inject creator from guice 2 my configuration works:
bind(PaymentFactory.class).toProvider(
FactoryProvider.newFactory(PaymentFactory.class, RealPayment.class));
The only workaround I found so far is to remove the generic parameter from the return type of the factory method:
public interface PaymentFactory {
Payment create(Date date);
}
Does anybody know, why guice 3 doesn't like the generic parameter in the factory method or what I generally misunderstood about assisted inject factories? Thanks!
There are two issues with your code above.
First, RealPayment implements Payment<SwissFrancs>, but PaymentFactory.create returns Payment<Currency>. A Payment<SwissFrancs> cannot be returned from a method that returns Payment<Currency>. If you change the return type of create to Payment<? extends Currency>, then RealPayment will work (because it's a Payment for something that extends Currency).
Second, you DO need to use the version of implement that takes a TypeLiteral as its first argument. The way to do that is to use an anonymous inner class. To represent `Payment' you can use
new TypeLiteral<Payment<? extends Currency>>() {}
See the Javadoc for that TypeLiteral constructor for more information.