Inject list of beans implementing same interface - java

Supposing I have following interface
public interface Handler {
void handle(Object o);
}
and implementations
public class PrintHandler implements Handler {
void handle(Object o) {
System.out.println(o);
}
}
public class YetAnotherHandler implements Handler {
void handle(Object o) {
// do some stuff
}
}
I want to inject all Handler subclasses into some class
public class Foo {
private List<Handler> handlers;
}
How can I achieve this using Quarkus?

All the implementation needs to be marked for #ApplicationScoped like:
#ApplicationScoped
public class PrintHandler implements Handler {
public String handle() {
return "PrintHandler";
}
}
In the class where you want to inject all the implementations, use
#Inject
Instance<Handler> handlers;
This Instance is imported from javax.enterprise.inject.Instance;
This handlers variable will have all the implementations of Handler interface.
javax.enterprise.inject.Instance also implements the Iterable so you can iterate to it and call the required methods.
#Inject
Instance<Handler> handlers;
#GET
#Produces(MediaType.TEXT_PLAIN)
public List<String> handle() {
List<String> list = new ArrayList<>();
handlers.forEach(handler -> list.add(handler.handle()));
return list;
}

Related

How to inject all implementations of interface?

I have one interface (First) which I've implemented in two classes. Classes which implements the intereface I've annotated with #Stateless annotation, and interface is #Remote. Then i've created a Main interface with one method which should return First interface, it also annotated as #Remote. In implementation of Main int I've created an Instance<First> field ,and annotated it with #Inject , and Map<FirstType, First> which I'm initializing in setUp() method with #PostConstruct. When i try to invoke main.getFirst(FirstType.HELLO).getSomething() it throws a NullpointerExeption. How to fix this issue.
#Remote
public interface First {
String getSomething();
FirstType getType();
}
_
#Stateless
public class ActionFirstImpl implements First {
#Override
public String getSomething() {
return "Hello";
}
#Override
public FirstType getType() {
return FirstType.ACTION;
}
_
#Remote
public interface TestWSFactory {
First getFirst(FirstType type);
}
_
#Stateless
public class TestWSFactoryImpl implements TestWSFactory {
#Inject
Instance<First> firstList;
private Map<FirstType, First> map;
#PostConstruct
void setUp() {
map = new HashMap<>();
firstList.forEach(t -> map.put(t.getType(), t));
}
#Override
public First getFirst(FirstType type) {
return Optional.ofNullable(map.get(type)).orElse(null);
}
This pattern works perfectly with SpringBoot, but is it possible to do the same with jakarta-ee?

How to create a new instance of a bean for each generic type?

So I have my Subject class:
#Component
public class Subject<T extends Monitorable> {
#Autowired
private List<Observer<T>> observers;
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
Is that a way to create a new subject instance for each implementation of Monitorable like:
#Autowired
private Subject<Trip> tripSubject;
Trip is a Monitorable and it has its own observers
#Autowired
private Subject<Truck> truckSubject;
and truck as well
The problem is. It creates only one Subject with all observers mixed how to separate them without create a new subject class for each monitorable?
This is not the answer to your question, but maybe a solution for your problem: Spring 4.2 has a build in event (observer) mechanism :
#Autowire ApplicationEventPublisher publisher;
public void doSomething() {
...
//fire the event
publisher.publishEvent(new YourEvent());
...
}
Some other bean:
//This is the observer, it "catch" the event
#EventListener
public void handleOrderCreatedEvent(YourEvent your) {
...
}
It is pretty simple. You could do it in a few ways, one of them is just create #Configuration and defind separate method for each required instance.
First, do remove #Component annotation from Subject definition:
//#Component
public class Subject<T extends Monitorable> {
}
Second, do define custom configuration with #Configuration:
#Configuration
public class MonitorableConfiguration {
#Bean
public Subject<Trip> tripSubject() {
return new Subject<>();
}
#Bean
public Subject<Truck> documentSubject() {
return new Subject<>();
}
}
Third, do use #Qualified to select required instance of Subject bean:
#Service
public class BusinessLogicService {
#Autowired
#Qualifier("tripSubject")
private Subject<Trip> tripSubject;
#Autowired
#Qualifier("documentSubject")
private Subject<Truck> documentSubject;
}
NOTE
In this situation, I would reccomend to go a little bit further. It could be more readable from my point of view.
First, do remove #Component annotation from Subject definition:
//#Component
public class Subject<T extends Monitorable> {
}
Second, do declare separate class definition for all required types:
#Component
public class TripSubject extends Subject<Trip> {
}
#Component
public class TruckSubject extends Subject<Truck> {
}
Third use is as any other singletons cope beans:
#Service
public class BusinessLogicService {
#Autowired
private TripSubject tripSubject;
#Autowired
private TruckSubject documentSubject;
}
I improved oleg.cheredinik answer because there is no way to do it. Here's what I think is the best solution:
I changed Subject to receive Observer as construct params
public class Subject<T extends Monitorable> {
private final List<Observer<T>> observers;
public Subject(final List<Observer<T>> observers) {
this.observers = observers;
}
public void fireListeners(T monitorable){
for (Observer<T> observer : observers) {
observer.doSome(monitorable);
}
}
}
and then I created subject with SubjectSimpleFactory :
#Configuration
public class SubjectSimpleFactory {
#Bean
#Autowired(required = false)
public Subject<Trip> getTripSubject( Optional<List<Observer<Trip>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
#Bean
#Autowired(required = false)
public Subject<Truck> getTruckSubject( Optional<List<Observer<Truck>>> observers){
return new Subject<>(getListenersIfPresent(observers));
}
}
private static <M extends Monitorable> List<Observer<M>> getListenersIfPresent(
final Optional<List<Observer<M>>> observers )
{
return observers.isPresent() ? observers.get() : Collections.emptyList();
}
In this way my observers are not mixed and I only have to create one class without repeat code or subclass Subject and I can use generic type as qualifier as well
#Service
#Scope("prototype")
public class Subject<T extends Monitorable> {
}
#Component
public class RunSubject {
#Autowired
private Subject<Monitorable1> subject1;
#Autowired
private Subject<Monitorabl2> subject2;
public void run(ApplicationArguments args) throws Exception {
System.out.println(subject1);
System.out.println(subject2);
}
}

Spring Bean Factory Using Class Name

I have an interface/implementation like so:
public interface Processor {
void processMessage(Message m);
}
#Component
public class FooAProcessor implements Processor {
private FooA fooA;
public FooAProcessor(FooA fooA) {
this.fooA = fooA;
}
#Override
public void processMessage(Message m) {
//do stuff
}
}
#Component
public class FooBProcessor implements Processor {
private FooA fooA;
public FooBProcessor(FooA fooA) {
this.fooA = fooA;
}
#Override
public void processMessage(Message m) {
//do stuff
}
}
The FooA bean is simple, like this:
#Component
public class FooA {
//stuff
}
And the message class:
public class Message {
private Class clazz;
}
I am pulling messages off a queue. I need to provide a concrete Processor to handle the different types of messages appropriately. Here's the message receiver:
public class MessageReceiver {
public void handleMessage(Message m) {
Processor processor = //get concrete implementation from Message clazz
processor.processMessage(m);
}
}
How exactly can I use the class name/object to define a concrete implementation of Processor?
My first thought was to develop some sort of a factory that takes in a class and provides the concrete implementation. Something like this:
#Component
public class ProcessorFactory {
private FooAProcessor fooAProcessor;
private FooBProcessor fooBProcessor;
public ProcessorFactory(FooAProcessor fooAProcessor, FooBProcessor fooBProcessor) {
this.fooAProcessor = fooAProcessor;
this.fooBProcessor = fooBProcessor;
}
public Processor getFactory(Class clazz) {
if(clazz.isAssignableFrom(FooAProcessor.class)) {
return fooAProcessor;
}
}
}
Or to use the application context like this:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getBean(clazz);
Is this the best way to go about this problem? Is there a better practice?
You can inject ApplicationContext into your factory and get beans from there:
#Component
public class Factory {
#Autowired ApplicationContext applicationContext;
public Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
Or you can put your processors into map and get them from it:
#Component
public class ProcessorFactory {
private final Processor fooAProcessor;
private final Processor fooBProcessor;
private final Map<Class<T extends Processor>, Processor> beanMap;
public ProcessorFactory (Processor fooAProcessor, Processor fooBProcessor) {
this.fooAProcessor = fooAProcessor;
this.fooBProcessor = fooBProcessor;
this.beanMap = new HashMap(2);
}
#PostConstruct
public void init() {
beanMap.put(FooAProcessor.class, fooAProcessor);
beanMap.put(FooBProcessor.class, fooBProcessor);
}
public Processor getProcessor(Class<T extends Processor> clazz) {
return beanMap.get(clazz);
}
}
I recommend to not rely on class when working with spring context but use beanNames instead.

Spring choose bean implementation at runtime

I'm using Spring Beans with annotations and I need to choose different implementation at runtime.
#Service
public class MyService {
public void test(){...}
}
For example for windows's platform I need MyServiceWin extending MyService, for linux platform I need MyServiceLnx extending MyService.
For now I know only one horrible solution:
#Service
public class MyService {
private MyService impl;
#PostInit
public void init(){
if(windows) impl=new MyServiceWin();
else impl=new MyServiceLnx();
}
public void test(){
impl.test();
}
}
Please consider that I'm using annotation only and not XML config.
1. Implement a custom Condition
public class LinuxCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux"); }
}
Same for Windows.
2. Use #Conditional in your Configuration class
#Configuration
public class MyConfiguration {
#Bean
#Conditional(LinuxCondition.class)
public MyService getMyLinuxService() {
return new LinuxService();
}
#Bean
#Conditional(WindowsCondition.class)
public MyService getMyWindowsService() {
return new WindowsService();
}
}
3. Use #Autowired as usual
#Service
public class SomeOtherServiceUsingMyService {
#Autowired
private MyService impl;
// ...
}
Let's create beautiful config.
Imagine that we have Animal interface and we have Dog and Cat implementation. We want to write write:
#Autowired
Animal animal;
but which implementation should we return?
So what is solution? There are many ways to solve problem. I will write how to use #Qualifier and Custom Conditions together.
So First off all let's create our custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public #interface AnimalType {
String value() default "";
}
and config:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class AnimalFactoryConfig {
#Bean(name = "AnimalBean")
#AnimalType("Dog")
#Conditional(AnimalCondition.class)
public Animal getDog() {
return new Dog();
}
#Bean(name = "AnimalBean")
#AnimalType("Cat")
#Conditional(AnimalCondition.class)
public Animal getCat() {
return new Cat();
}
}
Note our bean name is AnimalBean. why do we need this bean? because when we inject Animal interface we will write just #Qualifier("AnimalBean")
Also we crated custom annotation to pass the value to our custom Condition.
Now our conditions look like this (imagine that "Dog" name comes from config file or JVM parameter or...)
public class AnimalCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (annotatedTypeMetadata.isAnnotated(AnimalType.class.getCanonicalName())){
return annotatedTypeMetadata.getAnnotationAttributes(AnimalType.class.getCanonicalName())
.entrySet().stream().anyMatch(f -> f.getValue().equals("Dog"));
}
return false;
}
}
and finally injection:
#Qualifier("AnimalBean")
#Autowired
Animal animal;
You can move the bean injection into the configuration, as:
#Configuration
public class AppConfig {
#Bean
public MyService getMyService() {
if(windows) return new MyServiceWin();
else return new MyServiceLnx();
}
}
Alternatively, you may use profiles windows and linux, then annotate your service implementations with the #Profile annotation, like #Profile("linux") or #Profile("windows"), and provide one of this profiles for your application.
Autowire all your implementations into a factory with #Qualifier annotations, then return the service class you need from the factory.
public class MyService {
private void doStuff();
}
My Windows Service:
#Service("myWindowsService")
public class MyWindowsService implements MyService {
#Override
private void doStuff() {
//Windows specific stuff happens here.
}
}
My Mac Service:
#Service("myMacService")
public class MyMacService implements MyService {
#Override
private void doStuff() {
//Mac specific stuff happens here
}
}
My factory:
#Component
public class MyFactory {
#Autowired
#Qualifier("myWindowsService")
private MyService windowsService;
#Autowired
#Qualifier("myMacService")
private MyService macService;
public MyService getService(String serviceNeeded){
//This logic is ugly
if(serviceNeeded == "Windows"){
return windowsService;
} else {
return macService;
}
}
}
If you want to get really tricky you can use an enum to store your implementation class types, and then use the enum value to choose which implementation you want to return.
public enum ServiceStore {
MAC("myMacService", MyMacService.class),
WINDOWS("myWindowsService", MyWindowsService.class);
private String serviceName;
private Class<?> clazz;
private static final Map<Class<?>, ServiceStore> mapOfClassTypes = new HashMap<Class<?>, ServiceStore>();
static {
//This little bit of black magic, basically sets up your
//static map and allows you to get an enum value based on a classtype
ServiceStore[] namesArray = ServiceStore.values();
for(ServiceStore name : namesArray){
mapOfClassTypes.put(name.getClassType, name);
}
}
private ServiceStore(String serviceName, Class<?> clazz){
this.serviceName = serviceName;
this.clazz = clazz;
}
public String getServiceBeanName() {
return serviceName;
}
public static <T> ServiceStore getOrdinalFromValue(Class<?> clazz) {
return mapOfClassTypes.get(clazz);
}
}
Then your factory can tap into the Application context and pull instances into it's own map. When you add a new service class, just add another entry to the enum, and that's all you have to do.
public class ServiceFactory implements ApplicationContextAware {
private final Map<String, MyService> myServices = new Hashmap<String, MyService>();
public MyService getInstance(Class<?> clazz) {
return myServices.get(ServiceStore.getOrdinalFromValue(clazz).getServiceName());
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
myServices.putAll(applicationContext.getBeansofType(MyService.class));
}
}
Now you can just pass the class type you want into the factory, and it will provide you back the instance you need. Very helpful especially if you want to the make the services generic.
Simply make the #Service annotated classes conditional:
That's all. No need for other explicit #Bean methods.
public enum Implementation {
FOO, BAR
}
#Configuration
public class FooCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.FOO == implementation;
}
}
#Configuration
public class BarCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.BAR == implementation;
}
}
Here happens the magic.
The condition is right where it belongs: At the implementating classes.
#Conditional(FooCondition.class)
#Service
class MyServiceFooImpl implements MyService {
// ...
}
#Conditional(BarCondition.class)
#Service
class MyServiceBarImpl implements MyService {
// ...
}
You can then use Dependency Injection as usual, e.g. via Lombok's #RequiredArgsConstructor or #Autowired.
#Service
#RequiredArgsConstructor
public class MyApp {
private final MyService myService;
// ...
}
Put this in your application.yml:
implementation: FOO
👍 Only the implementations annotated with the FooCondition will be instantiated. No phantom instantiations. 👍
Just adding my 2 cents to this question. Note that one doesn't have to implement so many java classes as the other answers are showing. One can simply use the #ConditionalOnProperty. Example:
#Service
#ConditionalOnProperty(
value="property.my.service",
havingValue = "foo",
matchIfMissing = true)
class MyServiceFooImpl implements MyService {
// ...
}
#ConditionalOnProperty(
value="property.my.service",
havingValue = "bar")
class MyServiceBarImpl implements MyService {
// ...
}
Put this in your application.yml:
property.my.service: foo
MyService.java:
public interface MyService {
String message();
}
MyServiceConfig.java:
#Configuration
public class MyServiceConfig {
#Value("${service-type}")
MyServiceTypes myServiceType;
#Bean
public MyService getMyService() {
if (myServiceType == MyServiceTypes.One) {
return new MyServiceImp1();
} else {
return new MyServiceImp2();
}
}
}
application.properties:
service-type=one
MyServiceTypes.java
public enum MyServiceTypes {
One,
Two
}
Use in any Bean/Component/Service/etc. like:
#Autowired
MyService myService;
...
String message = myService.message()

Spring proxy to choose implementation based on annotation and runtime value

I would like to inject a proxy implementation of an interface to a component and then let spring choose the right implementation based on a runtime property (and the value of an annotation at the implementation class). So my component does not have to care about choosing the right one.
It is kind of like a scope. But i think scopes are only for handling different instances of the same implementation class. Am i wrong with this?
I would like this to run for arbitrary interfaces without creating a service locator or some other construct for every new service.
Here is an example.
Suppose I have an interface defining a service
package test;
public interface IService {
void doSomething();
}
and two implementations:
package test;
import javax.inject.Named;
#Named
#MyAnnotation("service1")
public class Service1 implements IService {
#Override
public void doSomething() {
System.out.println("this");
}
}
...
package test;
import javax.inject.Named;
#Named
#MyAnnotation("service2")
public class Service2 implements IService {
#Override
public void doSomething() {
System.out.println("that");
}
}
Now I would like to inject an IService to another component and let spring choose the correct implementation based on some queryable run time property and the value of MyAnnotation.
Is there a way to do this in a general way in spring?
EDIT:
I have a Context that holds some value. It is a thread local in this case.
package test;
public class MyValueHolder {
private static final ThreadLocal<String> value = new ThreadLocal<>();
public static void set(String newValue) {
value.set(newValue);
}
public static String get() {
return value.get();
}
public static void reset() {
value.remove();
}
}
And I have an component which uses IService
package test;
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class MyComponent {
#Inject
private IService service;
public void myImportantWorkflow(){
MyValueHolder.set("service1");
service.doSomething();
MyValueHolder.set("service2");
service.doSomething();
}
}
The injected service should only be a proxy. Depending on the value set in MyValueHolder the call to doSomething should delegate to service1 or service2. So in this example it should delegate to doSomething on service1 in the first call and to service2 in the second call.
I could write such a delegator implementing the IService interface and use it for this one service. But then i have to repeat this for every other service . I hoped spring could do something like this with proxies almost by itself. Of course i have to provide some method to look beans up based on the value hold in the thread local and register it to spring. But i have no idea if that is even possible without modifying the spring framework. And if it is possible how to accomplish this.
You could use a ProxyFactoryBean to create the proxies and a TargetSource to do the lookup.
For example (not tested)
public class AnnotatedBeanTargetSource implements TargetSource, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
private Class<? extends Annotation> annotationType;
private Class<?> implementedIterface;
private Map<String, Object> beans;
#Override
public Class<?> getTargetClass() {
return this.implementedIterface;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
if (this.beans == null) {
this.beans = lookupTargets();
}
return this.beans.get(MyValueHolder.get());
}
protected Map<String, Object> lookupTargets() {
Map<String, Object> resolvedBeans = new HashMap<String, Object>();
String[] candidates = beanFactory.getBeanNamesForAnnotation(annotationType);
for (String beanName : candidates) {
Class<?> type = beanFactory.getType(beanName);
if (this.implementedIterface.isAssignableFrom(type)) {
Annotation ann = AnnotationUtils.getAnnotation(type, annotationType);
resolvedBeans.put((String) AnnotationUtils.getValue(ann), beanFactory.getBean(beanName));
}
}
return resolvedBeans;
}
#Override
public void releaseTarget(Object target) throws Exception {
// nothing to do
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
public Class<? extends Annotation> getAnnotationType() {
return annotationType;
}
public void setAnnotationType(Class<? extends Annotation> annotationType) {
this.annotationType = annotationType;
}
public Class<?> getImplementedIterface() {
return implementedIterface;
}
public void setImplementedIterface(Class<?> implementedIterface) {
this.implementedIterface = implementedIterface;
}
}
This is what I would do:
#Named
public class MyComponent {
// introduce a marker interface for Injecting proxies
#InjectDynamic
IService service
...
public void useIService() {
service.doSomething();
...
service.doSomethingElse();
...
service.doFinally();
}
}
Define a BeanPostProcessor that scans for bean with fields annotated with #InjectDynamic, then creates and inject a Proxy implementing the type required by the field.
The Proxy implementation will look in the applicationContext for beans implementing Supplier<T> (Java 8 or guava versions) where <T> is the type of the field annotated with #InjectDynamic.
Then you can define
#Name
public IServiceSupplier implements Supplier<IService> {
#Override
public IService get() {
// here you implement the look-up logic for IService
}
}
In this way the look-up of active the current implementation is decoupled from the Proxy and can be change by target type.

Categories

Resources