Inject multiple Spring beans, that inherit from shared interface, into an array within a service - spring

I came across a situation that I had in another project that I'm not exactly sure the best way to do within Grails. To set it up, this is what I'm doing in a plain Spring project.
I have two classes that inherit from the same interface:
public interface BaseInterface {
void doSomething();
}
public class Impl1 implements BaseInterface {
public void doSomething(){
System.out.println("doing impl 1");
}
}
public class Impl2 implements BaseInterface {
public void doSomething(){
System.out.println("doing impl 2");
}
}
So far pretty standard, I have N beans that I want to call sequentially to do work. (The example is obviously trivial). Within another Java class I can then do some magic to get all the beans injected(autowired) as an array.
#Autowired(required=false)
private BaseInterface[] theWorkers;
This will give me an array of worker beans as long as I have added them to the bean container in the configuration.
Now I'm trying to do the same thing in Grails. The same formula doesn't work. Putting the #Autowired portion in a service, and creating Impl1 and Impl2 within resources.groovy does not seem to do the job. So I'm wondering what the best solution is:
1) I'm missing something simple that will make this work very easily.
2) Do something similar to what's suggested by duffymo here. I'd create a named bean in resources.groovy that used a custom factory. That factory would emit a class that would contain all the classes implementing a certain interface. I'd use something similar to the suggestion to pull the services/classes matching the criteria then have that service allow someone to iterate over it's subclasses to do work.
3) Create a named bean for each of the Impl# classes within resources.groovy and then just use their distinct names and inject all of them into the classes individually. This option would not really scale or give much dynamism, but would work.

If you get access to the Spring application context you can call getBeansOfType which returns all known beans that implement a specified interface or extend a specified base class. So I'd register each bean in resources.groovy but also a manager class that gets a reference to the application context and finds the interface implementations for you. You said you want to call them sequentially, so you should implement the Ordered interface too.
Here's the manager class (put it in src/groovy/ in the correct folder for the package and rename it to whatever you want):
package com.foo
import org.springframework.beans.factory.InitializingBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class BaseInterfaceManager implements ApplicationContextAware, InitializingBean {
ApplicationContext applicationContext
List<BaseInterface> orderedImpls
void afterPropertiesSet() {
orderedImpls = applicationContext.getBeansOfType(BaseInterface).values().sort { it.order }
}
}
Then change the beans so they implement Ordered:
import org.springframework.core.Ordered;
public class Impl1 implements BaseInterface, Ordered {
public void doSomething(){
System.out.println("doing impl 1");
}
public int getOrder() {
return 42;
}
}
and
import org.springframework.core.Ordered;
public class Impl2 implements BaseInterface, Ordered {
public void doSomething(){
System.out.println("doing impl 2");
}
public int getOrder() {
return 666;
}
}
Register all three in resources.groovy (use whatever bean names you want):
beans = {
impl1(Impl1)
impl2(Impl2)
baseInterfaceManager(BaseInterfaceManager)
}
And then you can add a dependency injection in a service or controller or whatever for the baseInterfaceManager bean and use it to loop through the implementation classes in order:
class FooService {
def baseInterfaceManager
void someMethod() {
for (impl in baseInterfaceManager.orderedImpls) {
impl.doSomething()
}
}
}

Related

Generic type reverse lookup with Spring Boot #Service autowirings

Spring Boot & Java 11 here. I have an abstract base class:
public abstract class AbstractBurninator {
// ...
}
And some subclasses, such as:
public class FizzBurninator extends AbstractBurninator {}
public class BuzzBurninator extends AbstractBurninator {}
public class FoobazBurninator extends AbstractBurninator {}
But there are many more subclasses of it besides those three. I also have an interface:
public interface DoesThings<B extends AbstractBurninator> {
void doAllTheThings(B burninator, String payload);
}
So each implementation of the interface must specify the AbstractBurninator subclass it operates on. Hence I have:
public class DoesFizzThings implements DoesThings<FizzBurninator> {}
public class DoesBuzzThings implements DoesThings<BuzzBurninator> {}
public class DoesFoobazThings imlpements DoesThings<FoobazBurninator> {}
etc.
I now have a Spring Boot service (annotated with #Service) that gets autowired with a list of all List<DoesThings>. Inside that service I have a method that will infer (from certain logic) and instantiate an AbstractBurninator subclass, and it then needs to look up the DoesThings implementation associated with it. Hence if it infers an instance of FizzBurninator, I want it to select the DoesFizzThings instance from the autowired list:
#Service
public class BurninationService {
#Autowired
private List<DoesThings> thingDoers;
public void hahaha(Whistlefeather wf) {
// use 'wf' and other stateful data to infer a subclassed instance of 'AbstractBurninator':
AbstractBurninator burninator = inferSomehow();
// TODO: how to figure out which item of 'thingDoers' matches 'burninator'?
}
What's an easy and elegant way of doing this TBD lookup? I could inject a map instead:
private Map<AbstractBurninator,DoesThings> thingDoers;
But that seems unnecessary since each DoesThing has 1-and-only-1 corresponding AbstractBurninator. Any ideas? It's possible this can be done with straight Java generics, but I'm guessing Spring has some nifty utility that can help here.
If you are comfortable with wiring your Spring context into your service, you could do something like this (inspired by this SO accepted answer)
private <T extends AbstractBurninator> DoesThings<T> getSomeBurn(Class<T> clazz) {
String[] arr = ctx.getBeanNamesForType(ResolvableType.forClassWithGenerics(DoesThings.class, clazz));
if (arr.length == 1) {
return (DoesThings<T>) ctx.getBean(arr[0]);
} else {
throw new IllegalArgumentException("No burninator found");
}
}
This comes with a beautiful "unchecked cast" warning. Also, in my experience, wiring the application context indicates a design problem and definitely complicates testing.

SpringBoot: how to inject two classes having same name

In my application, I have two classes having the same name, but of course in different packages.
Both classes need to be injected in the application; Unfortunately, I get the following error message:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'myFeature' for bean class [org.pmesmeur.springboot.training.service.feature2.MyFeature] conflicts with existing, non-compatible bean definition of same name and class [org.pmesmeur.springboot.training.service.feature1.MyFeature]
My issue can be reproduced by the following sample:
#Component
#EnableConfigurationProperties(ServiceProperties.class)
public class MyService implements IService {
private final ServiceProperties serviceProperties;
private final IProvider provider;
private final org.pmesmeur.springboot.training.service.feature1.IMyFeature f1;
private final org.pmesmeur.springboot.training.service.feature2.IMyFeature f2;
#Autowired
public MyService(ServiceProperties serviceProperties,
IProvider provider,
org.pmesmeur.springboot.training.service.feature1.IMyFeature f1,
org.pmesmeur.springboot.training.service.feature2.IMyFeature f2) {
this.serviceProperties = serviceProperties;
this.provider = provider;
this.f1 = f1;
this.f2 = f2;
}
...
package org.pmesmeur.springboot.training.service.feature1;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature1;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
package org.pmesmeur.springboot.training.service.feature2;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature2;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
If I use different names for my classes MyFeature, my problem disappears!!!
I am used to work with Guice and this framework does not have this kind of problem/limitation
It seems that the spring dependencies injection framework uses only
the class-name instead of package-name + class-name in order to
select its classes.
In "real-life" I have this problem with a far-bigger project and I would strongly prefer not to have to rename my classes: can anyone help me?
One last point, I would prefer to avoid "tricks" such as using
#Qualifier(value = "ABC") when injecting my classes: in my sample,
there should be no ambiguity for finding the correct instance of
MyFeature as they do not implement the same interface
Simply re-implementing BeanNameGenerator adds a new problem for beans declared/instantiated by names
#Component("HelloWorld")
class MyComponent implements IComponent {
...
}
#Qualifier(value = "HelloWorld") IComponent component
I solved this issue by extending AnnotationBeanNameGenerator and redefining method buildDefaultBeanName()
static class BeanNameGeneratorIncludingPackageName extends AnnotationBeanNameGenerator {
public BeanNameGeneratorIncludingPackageName() {
}
#Override
public String buildDefaultBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
return beanDefinition.getBeanClassName();
}
}
You can assigna a value for each component e.g. #Component(value="someBean") and then inject it with #Qualifier e.g.
#Autowired
public SomeService(#Qualifier("someBean") Some s){
//....
}
Spring provides autowire by type and name. Your classname are same. By default spring considers only className not package. But you can override this behaviour by defining custom implementation of BeanNameGenerator interface in which you can generate name using both package and name. I am not providing code solution because i think you should explore more on this.
You can do something like this;
in package a
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
in package b
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
and in some config class;
#Configuration
public class Configuration {
#Bean
public a.MyFeature f1() {
return new a.MyFeature();
}
#Bean
public b.MyFeature f2() {
return new b.MyFeature();
}
}
Then you can autowire them with names f1 and f2, that are the names of their respective bean constructor methods.
You can do the similar thing with #Component("f1") &
#Component("f2")
Even though different interfaces are implemented and are in different packages, identical bean name causes this trouble, and you have to utilize some sort of custom naming to distinguish. Utilizing some custom Spring logic would be way too ugly compared to what you'd do with above solutions.

Spring Java Config reference in bean constructor to get other bean in constructed class

I've seen one of the program where MyConfig(Spring Configuration file) is being referenced in constructor of one of the bean in order to get other bean defined in MyConfig.
I am not sure about this kind of configuration. I can see cyclic reference in this kind of code, though it is working fine but I am not able to understand the flow. How it is working. Below is the replica of that code -
#Configuration
public class MyConfig {
#Bean(name="a")
#Scope("prototype")
public A getA() {
return new A();
}
#Bean(name="b")
#Scope("prototype")
public B getB() {
return new B();
}
#Bean(name="c")
#Scope("prototype")
public C getC() {
return new C();
}
#Bean(name="queueListener")
#Scope("singleton")
public Queue getQueue() {
return new Queue(MyConfig config);
}
}
Here is my Queue class -
public class Queue implements MessageListener{
private MyConfig config;
public Q(MyConfig config) {
this.config = config;
}
#Override
public void onMessage() {
createC();
}
public void createC() {
C cObj = config.getC();
cObj.setConfig(config);
cObj.performTask();
}
}
The class is "C" look like this-
public class C{
private transient MyConfig config;
private MyConfig config;
public C() {
}
public void setConfig(MyConfig config) {
this.config = config;
}
public MyConfig getConfig() {
return config;
}
public void performTask() {
A a = config.getA(); // Is it right way to get bean?
B b = config.getB();
}
}
So my question is that is it right way to get bean in another bean?
Will the return object really be spring bean object or simple java class object?
I can see cyclic reference in above code cause When instance of Queue class will be created inside MyConfig will take instance/reference of MyConfig.
Will this create cyclic reference?
My Architect has suggested me above approach instead of autoWiring Application context in both classes Queue and class "C". According to architect context is very heavy and it is not best practice.
What will be the execution cycle or call hierarchy when bean Queue is getting created?
It would be very much helpful to understand the working of above code.
It is a really bad idea to inject the configuration instance into a specific bean. It complicates your code and makes it inconvenient for testing because for testing Queue instance you should somehow mock the whole configuration.
If you want to inject a prototype bean to the singleton you can use a technique described here :
Howto generate prototype objects with in a singleton bean using spring java configurations
Please see example at Spring Boot #Autowired creating instances on a runtime
You can see how to use singleton and prototypes right way

Autowiring a list in spring, without configuration

How can I autowire a list using java, without configuration?
Say I have the following classes:
public abstract class A {
public abstract doStuff();
}
public class B extends A {
#Override
public void doStuff() {
System.out.println("I'm B");
}
}
public class C extends A {
#Override
public void doStuff() {
System.out.println("I'm C");
}
}
And I have the class
public class Aggregator {
#Autowired
private List<A> stuffDoers;
private void doAllStuff() {
for(A a:stuffDoers) {
a.doStuff();
}
}
}
How can I autowire some of A's implementation into the Aggregator without configuring a list in XML?
EDIT: I'm looking for a way to be able to control the members of a list
#Autowired always works with instances of a class, not types. You have defined 3 types: A, B and C, but have not created any instances from them.
To autowire, you need to create these instances, and also register them with Spring. This is where the XML config or Java config comes in. It is basically a short form for creating Spring-registered instances. So you can specify:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfiguration {
#Bean
public B someA() {
return new B();
}
#Bean
public C anotherA() {
return new C();
}
#Bean
public B evenMoreA() {
return new B();
}
}
This gives you 3 independent instance beans (not a list). For more details, see Java-based container configuration.
Now, Spring will do the job of finding all beans of type A in those packages, and populate your Aggregator class with all three beans correctly.
NOTE: These beans don't need to be in the same file. They can be declared anywhere in your #ComponentScan packages.
As asked in a comment, what if you want to have only some of those instances?
If you want only some of the beans added to your list, the situation is more tricky. You will need to move the excluded beans to a separate #Configuration class, in a different package. You should not add that new package to the Spring #ComponentScan packages, so Spring will not find those beans to add to the list. As far as I know, this is the only way.
Of course, if you want only a single bean, then as usual, you have to autowire it using #Qualifier and specify the bean name. In this case, you don't use a List, just the variable of type A.

Spring Autowiring not working for Abstract classes

I have a project where I have an interface, an Abstract class implementing the same interface and then a set of concrete classes which implement this interface and extend the Abstract Class.
public interface Invoice
{
void process();
}
#component
public abstract class AbstractInvoice(){
#Resource
protected Writer writer;
protected validateInvoice(){
//some implementation
}
}
#Component
public Class TypeAInvoice() extends AbstractInvoice implements Invoice{
#Override
public void process(){
//... some code
writer.write();
}
}
public Interface Writer(){
public void write();
}
#Component
public class CDWriter implements Writer{
#Override
public void write() { /* implementation.....*/}
}
Spring file has a component scan for the package.
<context:annotation-config>
<context:component-scan base-package="com.xyz" />
I am using a factory to get an instance of TypeAInvoice invoice
Now calling invoice.process() gets a NPE when getting to write.write()
I am not sure what am I missing here. I tried to see the component scan and scope and could not find anything conceptually wrong.
I am using a factory to get an instance of TypeAInvoice invoice
Depending on what your Factory does, this may be the problem. If the Factory creates a new TypeAInvoice, Spring wiring doesn't apply. You have to query the Spring context for the Bean. One way (though not very pretty) is to use ContextLoader:
return ContextLoader.getCurrentWebApplicationContext().getBean(TypeAInvoice.class)
I'd say static Factories and Spring don't go to well together. Spring stands for the Inversion of Control pattern, while Factories stand for the Service Locator pattern. I'd suggest that you get rid of your factories and autowire your Spring Beans.
Everything is good, except for the fact you use a factory to get the TypeAInvoice. If you create it like TypeAInvoice typer = new TypeAInvoice() then spring knows nothing of it, the Writer is not autowired, there for you get the NullPointerException. You should get the bean from the spring application context.
In my case, inside a Spring4 Application, i had to use a classic Abstract Factory Pattern(for which i took the idea from - http://java-design-patterns.com/patterns/abstract-factory/) to create instances each and every time there was a operation to be done.So my code was to be designed like:
public abstract class EO {
#Autowired
protected SmsNotificationService smsNotificationService;
#Autowired
protected SendEmailService sendEmailService;
...
protected abstract void executeOperation(GenericMessage gMessage);
}
public final class OperationsExecutor {
public enum OperationsType {
ENROLL, CAMPAIGN
}
private OperationsExecutor() {
}
public static Object delegateOperation(OperationsType type, Object obj)
{
switch(type) {
case ENROLL:
if (obj == null) {
return new EnrollOperation();
}
return EnrollOperation.validateRequestParams(obj);
case CAMPAIGN:
if (obj == null) {
return new CampaignOperation();
}
return CampaignOperation.validateRequestParams(obj);
default:
throw new IllegalArgumentException("OperationsType not supported.");
}
}
}
#Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
#Override
public void executeOperation(GenericMessage genericMessage) {
LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
}
}
Initially to inject the dependencies in the abstract class I tried all stereotype annotations like #Component, #Service etc but even though Spring context file had ComponentScanning for the entire package, but somehow while creating instances of Subclasses like CampaignOperation, the Super Abstract class EO was having null for its properties as spring was unable to recognize and inject its dependencies.After much trial and error I used this **#Configurable(dependencyCheck = true)** annotation and finally Spring was able to inject the dependencies and I was able to use the properties in the subclass without cluttering them with too many properties.
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
I also tried these other references to find a solution:
http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
Using abstract factory with Spring framework
Spring and Abstract class - injecting properties in abstract classes
Inject spring dependency in abstract super class
Spring autowire dependency defined in an abstract class
Spring can you autowire inside an abstract class?
Please try using **#Configurable(dependencyCheck = true)** and update this post, I might try helping you if you face any problems.
So precisely my point here is you don't need to get a bean from spring context all the time.

Resources