How to use Guice's AssistedInject factories along with service loader? - java

In my guice module I have multiple factories like shown below:
install(new FactoryModuleBuilder().implement(SportsCar.class,Ferrari.class).build(FerrariFactory.class));
install(new FactoryModuleBuilder().implement(LuxuryCar.class,Mercedes.class).build(MercedesFactory.class));
Both the factories have the following create method which takes an assisted element:
Ferrari create(#Assisted Element partsElement);
Mercedes create(#Assisted Element partsElement);
In a CarChooser class, I get instances of Ferrari or Mercedes as shown below:
#Inject
public CarChooser(FerrariFactory ferrariFactory , MercedesFactory mercedesFactory )
{
this.ferrariFactory = ferrariFactory;
this.mercedesFactory = mercedesFactory;
}
In the same class:
if(type.equals("ferrari"))
ferrariFactory.create(partsElement);
else if (type.equals("mercedes"))
mercedesFactory.create(partsElement);
...
Now, what I am trying is to make this CarChooser class open for extension but closed for modification. i.e. If I need to add another Factory, I shouldn't have to declare it as a variable + add it to the constructor + add another if clause for the corresponding new type. I was planning to use ServiceLoader here and declare an interface CarFactory which will be implemented by all factories (such as FerrariFactory, MercedesFactory etc.) and all implementations will have a getCarType method. But how can I call the create method using Service Loader ?
ServiceLoader<CarFactory> impl = ServiceLoader.load(CarFactory.class);
for (CarFactory fac: impl) {
if (type.equals(fac.getCarType()))
fac.create(partsElement);
}
}
Is the right way if it works (I am not even sure if this would work). Or Is there a better way of doing the same ?
Thanks to the first comment on the post, I know that I want to use MapBinder . I wrote a CarFactory which is extended by both FerrariFactory and MercedesFactory. So I add the following:
MapBinder<String, CarFactory> mapbinder = MapBinder.newMapBinder(binder(), String.class, CarFactory.class);
mapbinder.addBinding("Ferrari").to(FerrariFactory.class);
mapbinder.addBinding("Mercedes").to(MercedesFactory.class);
But since the .to portion of the above code is abstract class I get an initialisation error that FerrariFactory is not bound to any implementation. What should I have here to bind it to the correct Assisted Inject Factory declared with the FactoryModuleBuilder ?

So, using a MapBinder along with generics is the solution.
install(new FactoryModuleBuilder().implement(SportsCar.class,Ferrari.class).build(FerrariFactory.class));
install(new FactoryModuleBuilder().implement(LuxuryCar.class,Mercedes.class).build(MercedesFactory.class));
MapBinder<String, CarFactory<?>> mapbinder = MapBinder.newMapBinder(binder(), new TypeLiteral<String>(){}, new TypeLiteral<CarFactory<?>>(){});
mapbinder.addBinding("ferrari").to(FerrariFactory.class);
mapbinder.addBinding("mercedes").to(MercedesFactory.class);
The important thing here to note is that this seems to be supported only in Guice 3.0 + JDK 7. For JDK 8, you need Guice 4.0 ! Found this problem on https://github.com/google/guice/issues/904
Hope that helps.
More details regarding the solution:
http://crusaderpyro.blogspot.sg/2016/07/google-guice-how-to-use-mapbinder.html

Related

CDI: Dynamical injection of a group of classes how to?

I need to dynamically Inject a variable group of classes in my application. The purpose is, as the application grows, only have to add more classes inheriting the same interface. This is easy to do with tradicional java as I just need to search for all classes in a package and perform a loop to instantiate them. I want to do it in CDI. For example:
public MyValidatorInterface {
public boolean validate();
}
#Named
MyValidator1 implements MyValidatorInterface
...
#Named
MyValidator2 implements MyValidatorInterface
...
Now the ugly non real java code just to get the idea of what I want to do:
public MyValidatorFactory {
for (String className: classNames) {
#Inject
MyValidatorInterface<className> myValidatorInstance;
myValidatorInstance.validate();
}
}
I want to loop over all implementations found in classNames list (all will be in the same package BTW) and Inject them dynamically so if next week I add a new validator, MyValidator3, I just have to code the new class and add it to the project. The loop in MyValidatorFactory will find it, inject it and execute the validate() method on the new class too.
I have read about dynamic injection but I can't find a way to loop over a group of class names and inject them just like I used to Instantiate them the old way.
Thanks
What you are describing is what Instance<T> does.
For your sample above, you would do:
`#Inject Instance<MyValidatorInterface> allInstances`
Now, allInstances variable contains all your beans which have the given Type (MyValidatorInterface). You can further narrow down the set by calling select(..) based on qualifiers and/or class of bean. This will again return an Instance but with only a subset of previously fitting beans. Finally, you call get() which retrieves the bean instance for you.
NOTE: if you call get() straight away (without select) in the above case, you will get an exception because you have two beans of given type and CDI cannot determine which one should be used. This is implied by rules of type-safe resolution.
What you most likely want to know is that Instance<T> also implements Iterable so that's how you get to iterate over the beans. You will want to do something like this:
#Inject
Instance<MyValidatorInterface> allInstances;
public void validateAll() {
Iterator<MyValidatorInterface> iterator = allInstances.iterator();
while (iterator.hasNext()) {
iterator.next().callYourValidationMethod();
}}
}

Interface to concrete class conditional instantiation in Spring

I have a Spring based Java application where a lot of classes use the following autowired interface.. they work off this interface at all places.
#Autowired
private IOperatingSystemManager m_operatingSystemManager;
Right now, there is only one implementation of the interface as follows:
#Component
public class WindowsManager implements IOperatingSystemManager
{
// Windows based shenanigans
}
And the application works as expected. Spring is happy. Everybody is happy.
Alright, not everybody...
So, I want to add another concrete implementation of IOperatingSystemManager ..
#Component
public class LinuxManager implements IOperatingSystemManager
{
// Linux based shenanigans
}
What we want is the auto wiring of IOperatingSystemManager conditionally based on a properties file setting. (say.. os=windows.. basically something that is an arbitrary string and cannot be derived from system properties etc. simply because this is a dummy example. the actual managers are not OS related.)
I don't want to change any of the classes who have autowired to the interface and are working off the interface. All I need is for Spring to look at some logic that will dictate the Autowiring of the variables and wire up the right concrete instance for:
#Autowired
IOperatingSystemManager m_operatingSystemManager
at all the gazillion places.
The documentation & web search talk about profiles, condition, bean factory, qualifiers etc.. but we don't want to use Profiles; and Qualifiers seem to be needing changes to all the interface variable annotations.
Factory methods look promising, but being new to Spring, couldn't find a crisp answer.
What is a simple and recommended way to achieve this?
Instead of scanning the WindowsManager class, create one concrete instance that implements the IOperatingSystemManager interface or another one, depending on the your logical conditions.
First, remove the #Component annotation from the WindowsManager class.
Then, create and scan this #Configuration class, which will act as a factory for your beans:
#Configuration
public class OperatingSystemManagerFactory {
#Bean
public IOperatingSystemManager getOperatingSystemManager() {
if ( /* some logic that evaluates to true if windows */ ) {
return new WindowsManager();
} else {
// Linux default option ;)
return new LinuxManager();
}
}
}
With this solution, you shouldn't need to update anyone of your classes that reference the IOperatingSystemManager interface.
I dont know which version of spring you are using but you have options for this
http://www.intertech.com/Blog/spring-4-conditional-bean-configuration/
Here, as you can see, you can create a bean based on a condition that you can decide. It actully gave your example, Windows and Linux :), so i believe thats what you are looking for.
Edit:
If you are using spring-boot, you have some other Conditional annotations
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-condition-annotations

Can I use some kind of assisted Inject with Dagger?

With Google Guice or Gin I can specify parameter with are not controlled by the dependency injection framework:
class SomeEditor {
#Inject
public SomeEditor(SomeClassA a, #Assisted("stage") SomeClassB b) {
}
}
The assisted parameter stage is specified at the time an instance of SomeEditor is created.
The instance of SomeClassA is taken from the object graph and the instance of SomeClassB is taken from the caller at runtime.
Is there a similar way of doing this in Dagger?
UPDATE: As of Dagger 2.31 from January 2021, Dagger now natively supports assisted injection, which is recommended over the Square and Auto options. (Those other options still work, but may require extra setup compared to the native option.)
class SomeEditor {
#AssistedInject public SomeEditor(
SomeClassA a, #Assisted SomeClassB b) {
// ...
}
}
#AssistedFactory interface SomeEditorFactory {
SomeEditor create(SomeClassB b);
}
(original answer)
Because factories are a separate type of boilerplate to optimize away (see mailing list discussion here), Dagger leaves it to a sister project, AutoFactory. This provides the "assisted injection" functionality Guice offers via FactoryModuleBuilder, but with some extra benefits:
You can keep using AutoFactory with Guice or Dagger or any other JSR-330 dependency injection framework, so you can keep using AutoFactory even if you switch between them.
Because AutoFactory generates code, you don't need to write an interface to represent the constructor: AutoFactory will write a brand new type for you to compile against. (You can also specify an interface to implement, if you'd prefer, or if you're migrating from Guice.)
Because all the type inspection happens at compile-time, it produces plain old Java, which doesn't have any slowness due to reflection and which works well with debuggers and optimizers. This makes the Auto library particularly useful for Android development.
Example, pulled from AutoFactory's README, which will produce a SomeClassFactory with providedDepA in an #Inject-annotated constructor and depB in a create method:
#AutoFactory
final class SomeClass {
private final String providedDepA;
private final String depB;
SomeClass(#Provided #AQualifier String providedDepA, String depB) {
this.providedDepA = providedDepA;
this.depB = depB;
}
// …
}
Just like #xsveda, I also wrote an answer about this in this other question, which I'll also reproduce here.
Today, for assisted injection with Dagger you probably want to use AssistedInject. I wrote about it in this blogpost, but I'll add a full example here to make things easier.
First thing you need are the dependencies:
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
Then here's how it can look like:
class ImageDownloader #AssistedInject constructor(
private val httpClient: HttpClient,
private val executorService: ExecutorService,
#Assisted private val imageUrl: URL,
#Assisted private val callback: ImageCallback
) {
#AssistedInject.Factory
interface Factory {
fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
}
}
First thing is that instead of annotating the constructor with #Inject, we annotate it with #AssistedInject. Then we annotate the parameters that will have to go through the factory, which is the opposite of what AutoFactory expects. Finally, we need an inner factory interface annotated with #AssistedInject.Factory that has a single method that receives the assisted parameters and returns the instance we're interested in.
Unfortunately, we still have an extra step here:
#AssistedModule
#Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
We don't necessarily need a dedicated module for it, even though that's a valid option. But we can also have those annotations in another module that is already installed in the component. The nice thing here is that we only need to do it once, and after that any factory will automatically become part of the graph.
With that, you can basically inject the factory and ask for your object as you'd normally do.
Yes, please check this Square project: square/AssistedInject
Currently it is not in 1.0 yet for purpose. They wait until Dagger will introduce a public API for registering those generated Module classes automatically - see this issue. With that you won't have to reference them in your Dagger code as in this example from README:
#AssistedModule
#Module(includes = AssistedInject_PresenterModule.class)
abstract class PresenterModule {}

Guice equivalent of Spring's #Autowire list of instances

In spring when I do:
#Autowire
List<MyInterface> myInterfaces;
then this list will get populated by all beans which implement MyInterface. I didn't have to create bean of type List<MyInterface>.
I'm looking for such behaviour in Google Guice.
Sofar I went with:
Multibinder<MyInterface> myInterfaceBinder = MultiBinder.newSetBinder(binder(), MyInterface.class);
Now if I have a bean which implements MyInterface and I bind it, say via:
bind(MyInterfaceImpl.class).asEagerSingleton();
it won't be included in my multibinder. I need to add:
myInterfaceBinder.addBinding.to(MyInterfaceImpl.class);
This is somewhat more complicated than what Spring offers. So I was wonmdering whether I'm not using it in wrong way. So is there easier way of achieving this?
I haven't used it that way myself, yet, but according to Guice's API documentation, I think you should be able to write something not much more than this once:
bindListener(Matchers.subclassesOf(MyInterface.class), new TypeListener() {
public <I> void hear(TypeLiteral<I> typeLiteral,
TypeEncounter<I> typeEncounter) {
myInterfaceBinder.addBinding().to(typeLiteral);
}
}
Then, when you bind an implementation via
bind(MyInterfaceImpl.class).asEagerSingleton();
it should be added to your multibinder automatically.
A hacky solution would be to do it all in a loop:
Multibinder<MyInterface> myInterfaceBinder
= MultiBinder.newSetBinder(binder(), MyInterface.class);
Class<? extends MyInterface>[] classes = {
MyInterfaceImpl,
YourInterfaceImpl.class,
MyCatsInterfaceImpl
};
for (Class<? extends MyInterface> c : classes) {
bind(c).asEagerSingleton();
myInterfaceBinder.addBinding.to(c);
}
It's hacky, it's applicable for such simple cases only, but it's simple and DRY.

Java - Register all classes annotated with #MyAnnotation

I have an annotation #MyAnnotation and I can annotate any type (class) with it. Then I have a class called AnnotatedClassRegister and I would like it to register all classes annotated with #MyAnnotation so I can access them later. And I'd like to register these classes automatically upon creation of the AnnotatedClassRegister if possible, and most importantly before the annotated classes are instantiated.
I have AspectJ and Guice at my disposal. The only solution I came up with so far is to use Guice to inject a singleton instance of the AnnotatedClassRegister to an aspect, which searches for all classes annotated with #MyAnnotation and it adds the code needed to register such class in its constructor. The downside of this solution is that I need to instantiate every annotated class in order for the code added by AOP to be actually run, therefore I cannot utilize lazy instantiation of these classes.
Simplified pseudo-code example of my solution:
// This is the class where annotated types are registered
public class AnnotatedClassRegister {
public void registerClass(Class<?> clz) {
...
}
}
// This is the aspect which adds registration code to constructors of annotated
// classes
public aspect AutomaticRegistrationAspect {
#Inject
AnnotatedClassRegister register;
pointcutWhichPicksConstructorsOfAnnotatedClasses(Object annotatedType) :
execution(/* Pointcut definition */) && args(this)
after(Object annotatedType) :
pointcutWhichPicksConstructorsOfAnnotatedClasses(annotatedType) {
// registering the class of object whose constructor was picked
// by the pointcut
register.registerClass(annotatedType.getClass())
}
}
What approach should I use to address this problem? Is there any simple way to get all such annotated classes in classpath via reflection so I wouldn't need to use AOP at all? Or any other solution?
Any ideas are much appreciated, thanks!
It's possible:
Get all paths in a classpath. Parse System.getProperties().getProperty("java.class.path", null) to get all paths.
Use ClassLoader.getResources(path) to get all resources and check for classes: http://snippets.dzone.com/posts/show/4831
It isn't simple that much is sure, but I'd do it in a Pure Java way:
Get your application's Jar location from the classpath
Create a JarFile object with this location, iterate over the entries
for every entry that ends with .class do a Class.forName() to get the Class object
read the annotation by reflection. If it's present, store the class in a List or Set
Aspects won't help you there, because aspects only work on code that's actually executed.
But annotation processing may be an Option, create a Processor that records all annotated classes and creates a class that provides a List of these classes
Well, if your AnnotatedClassRegister.registerClass() doesn't have to be called immediately at AnnotatedClassRegister creation time, but it could wait until a class is first instantiated, then I would consider using a Guice TypeListener, registered with a Matcher that checks if a class is annotated with #MyAnnotation.
That way, you don't need to search for all those classes, they will be registered just before being used. Note that this will work only for classes that get instantiated by Guice.
I would use the staticinitialization() pointcut in AspectJ and amend classes to your register as they are loaded, like so:
after() : staticinitialization(#MyAnnotation *) {
register.registerClass(thisJoinPointStaticPart.getSignature().getDeclaringType());
}
Piece of cake, very simple and elegant.
You can use the ClassGraph package like so:
Java:
try (ScanResult scanResult = new ClassGraph().enableAnnotationInfo().scan()) {
for (ClassInfo classInfo = scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName()) {
System.out.println(String.format("classInfo = %s", classInfo.getName()));
}
}
Scala:
Using(new ClassGraph().enableAnnotationInfo.scan) { scanResult =>
for (classInfo <- scanResult.getClassesWithAnnotation(classOf[MyAnnotation].getName).asScala) {
println(s"classInfo = ${classInfo.getName}")
}
}

Categories

Resources