class ClassA {
protected ClassA(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
}
}
class ClassB extends ClassA {
protected ClassB(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,
PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
super(baseGraph, context, api, locations, regionId, slicer, userExecutor);
}
}
class C extends AbstractModule {
protected void configure() {
bind(classA).to(classB);
}
}
There some problem in the constructor args while binding.
Error that am getting
Caused by: com.google.inject.CreationException: Guice creation errors:
1) No implementation for java.lang.String annotated with #com.google.inject.assistedinject.Assisted(value=) was bound.
while locating java.lang.String annotated with #com.google.inject.assistedinject.Assisted(value=)
for parameter 4 at
#Assisted is used in the context of assisted injection, which is a Guice feature that automatically implements a factory for you that mixes normal constructor parameters with Guice-provided parameter injections. For instance, here:
class ClassB extends ClassA {
protected ClassB(Injector baseGraph,
BlobStoreContext context,
SwiftApi api,
#Memoized Supplier<Set<? extends Location>> locations,
#Assisted String regionId,
PayloadSlicer slicer,
#Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
super(baseGraph, context, api, locations, regionId, slicer, userExecutor);
}
}
I would expect to see this interface:
public interface ClassBFactory {
ClassB create(String regionId);
}
Which you would then bind in your AbstractModule subclass like this:
install(new FactoryModuleBuilder().build(ClassBFactory.class));
Guice can then inspect the ClassBFactory interface, observe the ClassB return value, match the String regionId parameter of create to the #Assisted String regionId parameter of your constructor, and then provide this ClassBFactory instance to your graph. At that point, rather than injecting ClassB, you inject a ClassBFactory and then call classBFactory.create("foo") to create a ClassB with its regionId set to "foo".
However, if you try to inject ClassB rather than ClassBFactory, Guice will not give your #Assisted annotation any special treatment, and will not be able to inject that field. Search your codebase to see if a factory interface exists, and if not, you'll need to create one (or otherwise redesign your constructor).
Related
I have a class as follows
#Component
public abstract class NotificationCenter {
protected final EmailService emailService;
protected final Logger log = LoggerFactory.getLogger(getClass());
protected NotificationCenter(EmailService emailService) {
this.emailService = emailService;
}
protected void notifyOverEmail(String email, String message) {
//do some work
emailService.send(email, message);
}
}
EmailService is a #Service and should be auto-wired by constructor injection.
Now I have a class that extends NotificationCenter and should also auto-wire components
#Service
public class NotificationCenterA extends NotificationCenter {
private final TemplateBuildingService templateBuildingService;
public NotificationCenterA(TemplateBuildingService templateBuildingService) {
this.templateBuildingService = templateBuildingService;
}
}
Based on the above example the code won't compile because there is no default constructor in the abstract class NotificationCenter unless I add super(emailService); as the first statement to NotificationCenterA constructor but I don't have an instance of the emailService and I don't intend to populate the base field from children.
Any idea what's the proper way to handle this situation? Maybe I should use field injection?
NotificationCenter is not a real class but an abstract class, so you can't create the instance of it. On the other hand, it has a field (final field!) EmailService that has to be initialized in constructor! Setter won't work here, because the final field gets initialized exactly once. It's Java, not even Spring.
Any class that extends NotificationCenter inherits the field EmailService because this child "is a" notification center
So, you have to supply a constructor that gets the instance of email service and passes it to super for initialization. It's again, Java, not Spring.
public class NotificationCenterA extends NotificationCenter {
private final TemplateBuildingService templateBuildingService;
public NotificationCenterA(EmailService emailService, TemplateBuildingService templateBuildingService) {
super(emailService);
this.templateBuildingService = templateBuildingService;
}
}
Now spring manages beans for you, it initializes them and injects the dependencies.
You write something that frankly I don't understand:
...as the first statement to NotificationCenterA constructor but I don't have an instance of the emailService and I don't intend to populate the base field from children.
But Spring will manage only a NotificationCenterA bean (and of course EmailService implementation), it doesn't manage the abstract class, and since Java puts the restrictions (for a reason) described above, I think the direct answer to your question will be:
You can't use setter injection in this case (again, because of final, it is Java, not because of Spring)
Constructor injection, being in a general case better than setter injection can exactly handle your case
First point :
#Component is not designed to be used in abstract class that you will explicitly implement. An abstract class cannot be a component as it is abstract.
Remove it and consider it for the next point.
Second point :
I don't intend to populate the base field from children.
Without Spring and DI, you can hardcoded the dependency directly in the parent class but is it desirable ? Not really.
It makes the dependency hidden and also makes it much more complex to switch to another implementation for any subclass or even for testing.
So, the correct way is injecting the dependency in the subclass and passing the injected EmailService in the parent constructor :
#Service
public class NotificationCenterA extends NotificationCenter {
private final TemplateBuildingService templateBuildingService;
public NotificationCenterA(TemplateBuildingService templateBuildingService, EmailService emailService) {
super(emailService);
this.templateBuildingService = templateBuildingService;
}
}
And in the parent class just remove the useless #Component annotation.
Any idea what's the proper way to handle this situation? Maybe I
should use field injection?
Not it will just make your code less testable/flexible and clear.
using field injection would be the way to go since you mentioned you don't want to have the emailService in child class.
The other way you can try is to inject the EmailService bean into NotificationCenterA constructor, and then pass it to super(emailService).
So, it would be something like:
#Autowired
public NotificationCenterA(EmailService emailService, TemplateBuildingService templateBuildingService) {
super(emailService);
this.templateBuildingService = templateBuildingService;
}
You can also achieve this by using #Lookup annotation.
public abstract class NotificationCenter {
protected final Logger log = LoggerFactory.getLogger(getClass());
#Lookup
protected EmailService getEmailService() {
return null; // Spring will implement this #Lookup method using a proxy
}
protected void notifyOverEmail(String email, String message) {
//do some work
EmailService emailService = getEmailService(); // This is return the service bean.
emailService.send(email, message);
}
}
I have a Interface I and a Abstract Class A , I have My custom annotation MyAnnotation which should take parameter as subclass S of A, now while processing annotation I want to call method of concrete class S
public interface I{
void m1();
}
public abstract class A implements I {
public abstract void m1();
}
public #interface MyAnnotation {
public Class< ? extends A> ref();
public Class< ? super A> ref2();
}
public S extends A{
public void m1() {}
}
I am annotating method like
#MyAnnotation(ref= new XX() ) or #MyAnnotation(ref= XX.class )
#MyAnnotation(ref= new yy() ) or #MyAnnotation(ref= yy.class )
whichever works
//In spring aspect before processing I am getting method annotation and trying to call m1()
annotation.ref().m1() //Error
annotation.ref2().m1() //Error
You can't use new XX() in an annotation. Annotations parameters can use a very specific set of types:
primitive
String
Class
an Enum
another Annotation
an array of any of the above
See this answer.
So to accomplish what you're trying to accomplish, you'd have to use a class.
You would then have to use reflection to create an instance and invoke the method.
Class<?> clazz = annotation.ref();
I instance = (I) cls.getConstructor().newInstance();
instance.m1();
See this answer.
Your classes must all have no-argument constructors, else you'll only be able to instantiate some this way but not others (leading you to have to conditionally branch based on the class).
You can't do that simply like that. You need an instance of the class first.
If your A class is a Spring's bean, you can inject ApplicationContext and get the bean from there. Then you can call a method.
#Autowired
private ApplicationContext context;
void test(MyAnnotation annotation) {
A bean = context.getBean(annotation.ref());
bean.m1();
}
Let's say that there's class A that's constructor looks something like that:
public A(#Assited long id, #Assisten String name, ServiceA serviceA, ServiceB serviceB)
And there's AFactory:
public interface AFactory{
A create(long id, String name);
}
So to create an instance of A I obviously need to do something like that:
injector = Guice.createInjector(new MyModule());
AFactory af = injector.getInstance(AFactory .class);
A a = AFactory.create(100, "mike");
BUT,
Let's say I have other classes: Class B, Class C and Class D that has a member with type A, for example(with field injection but can be ctor also):
public class B{
#Inject
A a;
}
And I want that the same instance of A will be injected to those classes.
But still have the option to inject another instance of A to other classes (let's say Class E and F).
What is the correct way of doing that?
I just can't think of a clean way to do that.
You could structure your module to use Providers (I'm using #Provides methods below, but you can use full Provider classes or instances if you'd like), and mark the consistent A as #Singleton. If you want two bindings of A (consistent and inconsistent), at least one of them should be marked with a binding annotation; I'm using #Named here out of convenience, but you can use any binding annotation as listed in the docs.
public class AModule extends AbstractModule {
#Override public void configure() {
// Install your AFactory module. Here, injections for AFactory should succeed.
install(new FactoryModuleBuilder().build(AFactory.class));
}
/**
* Provides a singleton #Named("consistent") A.
* Inject #Named("consistent") A into B, C, and D; Guice will cache the instance.
*/
#Provides #Singleton #Named("consistent")
A provideConsistentA(AFactory factory) {
return factory.create(100, "mike");
}
/**
* Provides an unscoped A.
* Inject A without an annotation into E and F; each instance will be separate.
*/
#Provides #Singleton A provideUnscopedA(AFactory factory) {
return factory.create(200, "jeff");
}
}
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.
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.