Is it possible to wrap generic injections in some way?
Given the interface:
interface IFoo<T>
In my guice module:
bind((Key<IFoo<SomeType>) Key.get(Types.newParameterizedType(IFoo.class, SomeType.class))).to(Foo.class);
But before I return the Foo instance I want to wrap it with this:
class FooWrapper<T> implements IFoo<T> { public FooWrapper(Foo<T> foo) { ... } }
Somewhere like this:
return new FooWrapper<T>(foo);
Here's one way you can do this:
public class FooModule extends PrivateModule {
#Retention(RUNTIME) #BindingAnnotation
private #interface Internal {}
#Override protected void configure() {
bind(new TypeLiteral<IFoo<SomeType>>(){}).annotatedWith(Internal.class)
.to(new TypeLiteral<Foo<SomeType>>(){});
}
#Provides #Exposed IFoo<SomeType> provideFoo(#Internal IFoo<SomeType> foo) {
return new FooWrapper<SomeType>(foo);
}
}
Another thing that might work well would be to add a general annotation like #Wrapped and then to declare FooWrapper's constructor like this:
#Inject public FooWrapper(#Wrapped IFoo<T> foo) { ... }
Then in your private module you could bind Foo annotated with #Wrapped and bind and expose FooWrapper normally, without needing to use an #Provides method.
There may well be better ways of doing this I haven't thought of yet. Do also keep in mind that method interception is often a good way of decorating interface implementations with other behavior as well.
Related
I spent a plenty of time for finding any answers, but I think I have to ask.
I'm using Weld-SE for testing my entities.
I prepared entity randomizer for testing.
abstract class BaseEntityRandomizer<T extends BaseEntity>
implements Randomizer<T> {
#Override public T getRandomValue() {
...
}
}
class MySomeOtherEntityRandomizer
extends BaseEntityRandomizer<MySomeOther> {
#Override public MySomeOther getRandomValue() {
...
}
}
Now, with my test class, I want to inject those randomizers which each matches generic parameters
#ExtendWith(WeldJunit5Extension.class)
#AddPackages({BaseEntityRandomizer.class})
abstract class BaseEntityTest<T extends BaseEntity> {
#Test void doSome() {
}
#Inject
private BaseEntityRandomizer<T> entityRandomizer;
}
class MySomeOtherTest extends BaseEntityTest<MySomeOther> {
...
// I expect an instance of MySomeOtherRandomizer in injected
// into the entityRandomizer field.
}
Subclasses of randomizers and tests are prepared.
But I failed to make it work.
How can I make it work?
I tried with following factory class
class BaseEntityRandomizerFactory {
#Produces
public BaseEntityRandomizer<MySome> produceMySomeRandomizer() {
return new MySomeRandomizer();
}
}
I got
org.jboss.weld.exceptions.IllegalArgumentException:
WELD-001408: Unsatisfied dependencies for type BaseEntityRandomizer<T extends BaseEntity> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject protected transient ....BaseEntityTest.entityRandomizer
at ....BaseEntityTest.entityRandomizer(BaseEntityTest.java:0)
One way to achieve this is to use CDI Programmatic lookup. In your case, I'd start with #Inject Instance<Object> and then you can use subsequent calls to select() and get() methods to pick up whichever bean you desire. Usage looks something like this (assumes existence of beans with types Foo, Bar and List<String>):
#Inject
private Instance<Object> instance;
#Test void doSome() {
// selecting and obtaining instances of beans
Foo foo = entityRandomizer.select(Foo.class).get();
Bar bar = entityRandomizer.select(Bar.class).get();
// in case you need to select a parameterized type from instance, use TypeLiteral
List<String> listBean = entityRandomized..select( new TypeLiteral<List<String>>(){}).get()
}
Suppose I have a third party class as follows:
public class MyObject {
#Inject
public MyObject(Foo foo, Bar bar) { ... }
}
Now suppose that I have a factory interface like so:
public interface MyObjectFactory {
public MyObject build(Bar bar);
}
The idea is that I wish to have a MyObjectFactory that builds a MyObject for a fixed Foo - that is, essentially adding in the #Assisted annotation on the Bar constructor parameter from the outside. Of course, manually implementing MyObjectFactory is always possible:
public class MyObjectFactoryImpl implements MyObjectFactory {
#Inject private Provider<Foo> foo;
#Override
public MyObject build(Bar bar) { return new MyObject(foo.get(), bar); }
}
But let's say that there are conditions that require me to have Guice build MyObject instances - for example, method interceptors. This seems like a job for "injecting the injector":
public class MyObjectFactoryImpl implements MyObjectFactory {
#Inject private Injector injector;
#Override
public MyObject build(Bar bar) {
Injector child = injector.createChildInjector(new AbstractModule() {
#Override
protected void configure() {
bind(Bar.class).toInstance(bar);
// Set up method interceptors for MyObject here...
}
});
return child.getInstance(MyObject.class);
}
}
This sounds evil and boiler-plate-y, so I'm wondering if there are any alternate implementations and/or a way to have Guice generate the factory impl.
First of all, it is rare that you want to be passing instances of MyObject around in your class for exactly the reasons you describe. You have no control over them, so you can't add #Assisted annotations, you can't add method interceptors, etc. etc. Plus, what happens when you want to swap out the third party library for a different implementation?
Therefore, you should be wrapping MyObject into another object.
// **Please** choose better names than this in your real code.
public class MyWrapperBackedByMyObject implements MyWrapperInterface {
private final MyObject delegate;
#Inject
MyWrapperObject(Foo foo, #Assisted Bar bar) {
delegate = new MyObject(foo, bar);
}
#NotOnWeekends // Example of how you might do method interception
public void orderPizza() {
delegate.orderPizza();
}
}
Then, remove all references to MyObject throughout your code, using the naming convention I describe above, there should only be references to MyWrapperInterface.
actually it is. Have a look Assisted Inject
Include
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
Update injection with assisted
public class MyInjectedObject extends MyObject implements MyIntf {
#Inject
public MyObject(Foo foo, #Assisted Bar bar) { super(foo,bar); }
}
You have to add one more interface:
public interface MyIntf {}
In your module bind generic factory to your interface
install(new FactoryModuleBuilder()
.implement(MyIntf.class, MyInjectedObject.class)
.build(MyObjectFactory.class)
);
Now you can inject MyObjectFactory anywhere you want.
MyObject obj = myObjectFactory.build(bar);
I am wondering what the difference is between using #provides on a method and using bind() in my guice modules.
I usually override AbstractModule.configure() and bind all my implementations to my interfaces like this:
public class MyModule extends AbstractModule
{
#Override
protected void configure()
{
this.bind(myIface.class).to(myIfaceImpl.class);
this.bind(myOtherIface.class).to(myOtherIfaceImpl.class).asEagerSingleton();
}
...
}
However, I have noticed a pattern in the codebase I'm currently working with where implementations aren't bound explicitly they are being returned from providers like this:
public class MyModule extends AbstractModule
{
#Provides
#Singleton
myIface iFaceProvider()
{
return new myIfaceImpl();
}
...
}
Is there a reason to prefer one over the other? Are there cases that force a particular method?
If you do
bind(MyInterface.class).to(MyImplementation.class)
Guice creates the instance for you. This enables certiain things like AOP. If you do
#Provides
MyInterface provideMyInterface() {
return new MyImplementation();
}
then Guice didn't create the instance so AOP won't work. Also, it requires an accessible constructor for MyImplementation. Generally, this form is only used when you can't edit MyImplementation to make it Guice-compatible.
There's a third form:
#Provides
MyInterface provideMyInterface(MyImplementation impl) {
return impl;
}
which is almost totally equivalent to the bind(...).to(...) form. It is commonly used in frameworks like Dagger that do not have the bind syntax.
I'm trying to figure out the best practice for dealing with the following situation:
public class AppModule extends Module {
#Override
protected void configure() {
install(new JpaPersistModule("myJpaUnit").addFinder(Dao.class));
bind(MyJpaInitializer.class).asEagerSingleton();
}
#Provides
#IndicatesSomeConstantMap
#Singleton
Map<String, String> getMappings(Dao dao) {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
// Build map from Dao
return builder.build();
}
}
I need to inject #IndicatesSomeConstantMap in other classes. It seem the only way that getMappings can get the Dao is if I bind MyJpaInitializer as an EagerSingleton - which feels wrong. What's the preferred way of dealing with these hierarchical dependencies?
EDIT:
Based on the answer from #jeffcrowe I came up with something like:
public class Module1 extends PrivateModule {
#BindingAnnotation #Target({ FIELD, PARAMETER, METHOD }) #Retention(RUNTIME)
public #interface Jpa1{}
#Singleton
public static class JpaInitializer1 {
#Inject
public JpaInitializer1(#Jpa1 PersistService service) {
service.start();
}
}
public interface Finder1 {
#Finder(query="FROM Foo", returnAs = ArrayList.class)
List<Foo> getAll();
}
#Override
protected void configure() {
install(new JpaPersistModule("firstJpaUnit").addFinder(Finder1.class));
bind(JpaInitializer1.class);
}
#Provides
#Exposed
#Jpa1
PersistService getPersistService(Provider<PersistService> provider) {
return provider.get();
}
#Provides
#Exposed
#Jpa1
Finder1 getFinder(Finder1 finder, JpaInitializer1 init) {
return finder;
}
}
This handles the the dependency by wrapping it behind the provider and feels cleaner to me than using the eagerSingleton approach. This also hides the JpaModule behind a private module making it useful in a situation where multiple persistence modules are bound. The new problem is that since the Finder is already bound by the JpaPersistModule we have to add the #Jpa1 annotation to every injection of Finder1. Is there a way around that?
This is an interesting case. Normally in a scenario like this you could bind the initializer in normal Singleton scope and inject it into the Dao implementation, and this would ensure that it was done before the Dao was used. Due to the way the Jpa persistence modules are set up, there doesn't seem to be an easy way to add this dependency.
As the OP pointed out to me, JpaPersistModule is final, so we can't work around this by subclassing it. We can, however wrap the binder used to install the JpaPersistModule.
First wrap the binder in a proxy with an overridden the bind() method to intercept the EntityManager.class binding. (BinderProxy implements Binder and passes every call to the Binder given in it's constructor. Source available here)
new BinderProxy(binder()) {
#Override
public <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
if (clazz == EntityManager.class) {
return (AnnotatedBindingBuilder<T>) super.bind(clazz).annotatedWith(DefaultEntityManager.class);
} else {
return super.bind(clazz);
}
}
}.install(new JpaPersistModule("myJpaUnit"));
Then add a provides method to your module which ensures Jpa init before an EntityManager is used
#Provides EntityManager provideEm(MyJpaInitializer init, #DefaultEntityManager EntityManager em){
return em;
}
With Spring, you can define an array property and have Spring inject one of every (#Component) class that derives from the given type.
Is there an equivalent for this in Guice? Or an extension point to add this behavior?
This looks like a use case for Guice MultiBinder. You could have something like that:
interface YourInterface {
...
}
class A implements YourInterface {
...
}
class B implements YourInterface {
...
}
class YourModule extends AbstractModule {
#Override protected void configure() {
Multibinder.newSetBinder(YourInterface.class).addBinding().to(A.class):
Multibinder.newSetBinder(YourInterface.class).addBinding().to(B.class):
}
}
And you can inject a Set<YourInterface> anywhere:
class SomeClass {
#Inject public SomeClass(Set<YourInterface> allImplementations) {
...
}
}
That should match with what you need.
Guice Multibindings require you to explicitly addBinding() for A & B to YourInterface. If you would like a more "transparent" (automatic) solution such as what AFAIK Spring offers out-of-the-box, then assuming that Guice already knows about A & B because you already have a binding for A & B elsewhere anyway, even if not explicit but just implicit e.g. through an #Inject somewhere else, then and only then you alternatively could use something like this for auto-discovery (inspired by as done here, based on accessing Guice injector in a Module):
class YourModule extends AbstractModule {
#Override protected void configure() { }
#Provides
#Singleton
SomeClass getSomeClass(Injector injector) {
Set<YourInterface> allYourInterfaces = new HashSet<>();
for (Key<?> key : injector.getAllBindings().keySet()) {
if (YourInterface.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
YourInterface yourInterface = (YourInterface) injector.getInstance(key);
allYourInterfaces.add(yourInterface);
}
return new SomeClass(allYourInterfaces);
}
}
Note again that this approach does NOT require any classpath scanning; it just looks at all already known bindings in the Injector for anything that IS-A YourInterface.
Kotlin
Class SomeModule : AbstractModule() {
override fun configure() {
val myBinder: Multibinder<MyInterface> = Multibinder.newSetBinder(binder(), MyInterface::class.java)
myBinder.addBinding().to(Implementation1::class.java)
myBinder.addBinding().to(Implementation2::class.java)
}
Usage
#Inject constructor(private val someVar:Set<#JvmSuppressWildcards MyInterface>)