I've installed a factory in Google Guice with AssistedInject, but I get the following error (I'm running unit tests with JUnit):
com.google.inject.CreationException: Guice creation errors:
1) No implementation for clusterestimator.OptimalClusterEstimatorFactory was bound.
while locating clusterestimator.OptimalClusterEstimatorFactory
for parameter 0 at com.myfeed.algorithm.clusterer.tree.fca.BasicFCATreeFactory.<init>(BasicFCATreeFactory.java:16)
FCAModule.configure(FCAModule.java:29)
This error is the same even if I omit the install(new Factory...); line from my module, which makes me think that the line is somehow being ignored.
Here is the module code:
public class FCAModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder() // <-- Factory line that's not working
.implement(OptimalClusterEstimator.class, FCAOptimalClusterEstimator.class)
.build(OptimalClusterEstimatorFactory.class));
bind(ValueWell.class).to(MapBackedValueWell.class).asEagerSingleton();
bind(FCATreeFactory.class).to(BasicFCATreeFactory.class).asEagerSingleton();
bind(ItemFactory.class).to(MapBackedItemFactory.class).asEagerSingleton();
bind(ClustererFactory.class).asEagerSingleton();
bind(ClusterFactory.class).to(MemoryBackedClusterFactory.class).asEagerSingleton();
}
}
Here is the factory interface:
public interface OptimalClusterEstimatorFactory {
public <T> OptimalClusterEstimator createFCA(int kValue, ItemPointReducer<T> pointReducer);
}
Here is the constructor of FCAOPtimalClusterEstimator:
#AssistedInject
public FCAOptimalClusterEstimator(#Assisted int kValue, #Assisted ItemPointReducer<T> pointReducer) {
this.kValue = kValue;
this.pointReducer = pointReducer;
}
Here is the constructor for BasicFCATreeFactory, the first thing to call for the other factory. Note that this factory is not created using AssistedInject because it uses generics.
#Inject
public BasicFCATreeFactory(OptimalClusterEstimatorFactory optimalClusterEstimatorFactory, ClustererFactory clustererFactory, ClusterFactory clusterFactory) {
this.optimalClusterEstimatorFactory = optimalClusterEstimatorFactory;
this.clustererFactory = clustererFactory;
this.clusterFactory = clusterFactory;
}
For some unknown reason, removing the <T> generic part from the factory interface solved the problem. I've had previous issues with generics and Guice, so maybe this is just another one of those quirks because of type erasure.
So the factory interface is now:
public interface OptimalClusterEstimatorFactory {
public OptimalClusterEstimator createFCA(int kValue, ItemPointReducer pointReducer);
}
Guice assisted injection doesn't work well with generics. If you want to use generics then you have write your own factory.
Related
I am new to Guice and have done a lot of reading on this but I have not hand any success with this. I am basically creating a DAO and want to use Guice and the AssistedInjection. Effectively the end goal is create the Injected factory in other classes throughout the application.
Intended use in a actual class that would have the injection of the factory to then get classes from it
public class TestAllModelBootstrap {
#Inject private DAOFactory factory;
public TestAllModelBootstrap() {
}
#Test
public void testGettingDAO() {
Injector injector = Guice.createInjector(new HibernateDAOModule());
Token oToken = new OperTokenV1();
AccountingDAO accountingDAO = factory.create(oToken);
}
}
This is based on Guice-based code of:
public interface DAOFactory {
public AccountingDAO create(Token oTicket);
}
The concrete class has a constructor annoated
#Inject
public HibernateAccountingDAO(#Assisted Token oTicket) {
this.oTicket = oTicket;
}
And the actual Module:
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(AccountingDAO.class, HibernateAccountingDAO.class)
.build(DAOFactory.class));
bind(SessionFactoryInterface.class)
.toProvider(HibernateSessionProvider.class);
}
Each time I try to run this:
java.lang.NullPointerException -> indicating that the:
factory.create(oToken);
has factory as a null. In reading up on the problem I was lead to believe that the injection will not work like I am using it in the "test" class. It needs to be put in an "injected" class itself. But this doesn't work either - if I wrapper the Factory injection in another class and then try to use it, it doesn't work.
Any help would be appreciated...
TestAllModelBootstrap did not come from an Injector—JUnit created it instead—so Guice hasn't had a chance to inject it yet. Guice can only inject into objects that it creates via getInstance (and those objects' dependencies, recursively), or objects passed into injectMembers, or existing instances as requested using requestInjection.
You can manually get a factory instance:
factory = injector.getInstance(DAOFactory.class);
Or ask Guice to inject your members using injectMembers:
injector.injectMembers(this); // sets the #Inject factory field
Or use a tool like Guiceberry to inject your test cases across your app.
This question already has answers here:
Guice assisted injection deeper down the dependency hierarchy
(2 answers)
Closed 3 years ago.
I have recently learned about the AssistedInject extension to Guice and I thought it would be a nice solution to some design issues that I have. Unfortunately it seems that this solution is limited to just a one level assisted injection. Here comes an illustration of my problem - let's say we have three classes:
public class AImpl implements A{
#AssistedInject
public AImpl(#Assisted Integer number, B b){
}
}
public class BImpl implements B {
}
public class CImpl implements C {
#AssistedInject
public CImpl(A a){
}
}
a factory interface:
public interface CFactory {
C create(Integer number);
}
and a module:
public class ABCModule extends AbstractModule {
#Override
protected void configure() {
bind(A.class).to(AImpl.class);
bind(B.class).to(BImpl.class);
install(new FactoryModuleBuilder().implement(C.class, CImpl.class).build(CFactory.class));
}
public static void main(String[] args) {
Guice.createInjector(new ABCModule()).getInstance(CFactory.class).create(123);
}
}
Above fails with following stacktrace:
Exception in thread "main" com.google.inject.CreationException: Guice
creation errors:
1) Could not find a suitable constructor in stack.AImpl. Classes must
have either one (and only one) constructor annotated with #Inject or a
zero-argument constructor that is not private. at
stack.AImpl.class(AImpl.java:12) at
stack.ABCModule.configure(ABCModule.java:14)
2) stack.CImpl has #AssistedInject constructors, but none of them
match the parameters in method stack.CFactory.create(). Unable to
create AssistedInject factory. while locating stack.CImpl while
locating stack.C at stack.CFactory.create(CFactory.java:1)
2 errors at
com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:435)
at
com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:154)
at
com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
at com.google.inject.Guice.createInjector(Guice.java:95) at
com.google.inject.Guice.createInjector(Guice.java:72) at
com.google.inject.Guice.createInjector(Guice.java:62) at
stack.ABCModule.main(ABCModule.java:21)
This obviously means that I want too much from the extension - I hoped that the injector will search deep down in the dependecy tree searching for the #Assisted dependency. Is there any way to do this kind of assisted injection or do I need to implement my factory by myself?
Your code has a couple problems. You need to inject an "A" into "C" but your factory is set up to inject an integer
public interface CFactory {
C create(Integer number);
}
Also I don't think there is an #AssistedInject annotation provided by Guice. Use #Inject on the constructor instead, and mark the params you want to pass in with #Assisted
I'm using the #DeclareMixin provided by aspectjrt-1.6.11.
The situation is:
#Aspect
public class anAspect {
#DeclareMixin(value="#an.annotation.package.* *", interfaces = {
FirstInterface.class, SecondInterface.class, ThirdInterface.class
})
public AggregateInterface magicMethod(Object instance) {
return new AggregateInterfaceImpl(instance);
}
public interface AggregateInterface extends FirstInterface,
SecondInterface, ThirdInterface {
}
}
So when i compile via aspectj-maven-plugin-1.4, the compiler says that the factory method (magicMethod() in my case) does not return something that implements any of the interfaces implemented.
The problem came out when I've introduced the Second and Third interface in the AggregateInterfaceImpl.
Have you got any idea of the problem? Is there anything I did wrong?
Thanks.
I've resolved this issue declaring different mixins attached to different factory methods.
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.