Spring return dynamic instance based of String value - spring

Java Spring question:
I have a interface MyInterface with one method
void exec (String str);
I have many implementation of MyInterface, say Oneimpl, anotherimpl yetanotherimpl...and so on and can keep adding new implementations.
how do I obtain an instance of a specific implementation using just the name of the implementing class passed as a STRING value , say "someRandomImpl"
The code should be dynamic and can provide a instance of new implementations without code change.

implements ApplicationContextAware
it will autowired ApplicationContext object
use the object like
context.getBean(beanName)
then you get the bean

Related

Spring inject component into non-spring managed interface/abstract class and its subclasses

TLDR: I need an interface/abstract class and all classes implementing it to have access to a Spring managed bean. Can Spring inject a bean into an interface/abstract-class and its subclasses simply via #Autowired ?
I am working on an API built with Spring Webflux + Cloud Gateway that depending on the cookie JWT authorized party, identifies the User's policy group and assign an Attribute ENUM "InterfaceID" to the ServerWebExchange via exchange.getAttribute().put("InterfaceID",InterfaceID.A) after the JWT is validated, and currently uses "InterfaceID" to represent the different groups of users/different interface the user entered from.
JWTValidationFilter.java [Current]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put(InterfaceID.COMPANY_A_ACCESS);
break;
case "b":
exchange.getAttribute().put(InterfaceID.NORMAL_ACCESS);
...
}
For certain API endpoints (say /api/getSessionDocument), different "InterfaceID" fetches data from different DB/apis, as well as have different permission checking on top of that.
RequestController.java [Current]
#Autowired
APICallerUtil apiCallerUtil;
switch(exchange.getAttribute.get(InterfaceID)){
case "NORMAL_ACCESS":
apiCallerUtil.getDataFromApiA();
break;
case "COMPANY_A_ACCESS":
// call api B but check for permission from api D first
...
}
The endpoint's controller now has another switch statement, and to many code analyzers this have been a code smell. I have been trying to refactor this entire bit of code to use polymorphism to handle the different "getSessionDocument" flows, but i run into issues regarding the injection of util classes that calls specific APIs.
APICallerUtil.java class, exisiting class from the project, would prefer not to refactor this.
#Component
public class APICallerUtil{
#Value("${some uri to some API}") //different by environment and therefore cant be static final
private String uri1;
#Value("${some auth to some API}") //confidential
private String uri1AuthHeader;
//...
public JSONObject getDataFromApiA(String somekey){ //cant be static since uri1 is not static
//Some code that uses uri1 and apache httpclient
return data;
}
...
}
IBaseAccess.java
interface IBaseAccess{
default Mono<JSONObject> getSesssionDocument(ServerWebExchange e){return Mono.error("not implemented");}
}
RequestController.java [new]
#Autowired
APICallerUtil apiCallerUtil;
return exchange.getAttribute.get(InterfaceID).getSessionDocument(exchange);
NormalAccess.java
public class NormalAccess implements IBaseAccess{
//can i autowire APICallerUtil here?
//use constructor to pass the Util class reference here?
Mono<JSONObject> getSesssionDocument(ServerWebExchange e){
//need to call ApiA here
//need to call ApiC here
}
}
NormalAccess needs to call APICaller.getDataFromApiA(), but it needs a reference to the Spring managed instance of APICaller. What would be the "correct" way to pass the reference/autowire API caller into NormalAccess, or even better IBaseAccess (so that the implementing classes can use the Util bean)?
JWTValidationFilter.java [new]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put("InterfaceID",new CompanyAAccess(/*pass the util class here?*/));
break;
case "b":
exchange.getAttribute().put("InterfaceID",new NormalAccess(/*pass the util class here?*/));
...
}
I have tried several methods, but either I lack the knowledge on the specific Spring feature, or that method is deeemed a bad design choice by some, including:
Making the methods and fields in APICallerUtil static, via suggestions from Spring: How to inject a value to static field? and Assigning private static final field member using spring injection , then the Access classes can call the static methods.
Creating a contructor for IBaseAccess that consumes the APICallerUtil reference and store it inside. The JWTfilter would hold an autowired APICallerUtil and pass it in when the attribute is assigned.
Create a static class that provides the application context and Access classes use applicationContext.getBean("APICallerUtil"); to obtain the bean.
Use the #Configurable annotation? I could not find much documentation on how this works for interfaces/abstract-class.
I understand that there might not exist an absolute answer for this question, but regardless I'd like suggestion/feedback on which of these approaches are viable/good. Especailly concerning whether the APIUtil class should be static or not.

Multiple Constructor injection using Java Annotations

The SPRING doc says the following
Spring Framework 4.3, an #Autowired annotation on such a constructor
is no longer necessary if the target bean only defines one constructor
to begin with. However, if several constructors are available, at
least one must be annotated to teach the container which one to use.
As i understand if there are multiple constructors and we have not annotated any of them then i will get an error . I ran the following code
#Component // this is bean id
public class TennisCoach implements Coach {
private FortuneService fortuneservice;
public TennisCoach(FortuneService thefortuneservice) {
System.out.println(" inside 1 arg constructter");
fortuneservice = thefortuneservice;
}
public TennisCoach() {
System.out.println(" inside 0 arg constructter");
}
I call that using the below code
TennisCoach theCoach = myapp.getBean("tennisCoach", TennisCoach.class);
But i didn't get the error .I got the O/P as
inside 0 arg constructter
Why?
It looks like the text you've quoted from the Spring docs doesn't apply to a case where one of the constructors is a no-args (default) constructor. You can see this very easily if you try and add an bean reference parameter to it.
Spring attempts to determine the candidate constructors using AutowiredAnnotationBeanPostProcessor and in your scenario, will not find any single or autowired constructor, so it will record the no-args one and instantiate it in SimpleInstantiationStrategy.

Spring declaration by multiple interfaces

I have some architecture issue.
I have two different interfaces (IntefaceA, IntefaceB) and a class (MyClass), which implements these.
When I inject MyClass like this:
#Autowired
InterfaceA myClass;
I am not able to use implemented methods from InterfaceB.
My idea was to check with the instanceof MyClass, to be able to call the method from InterfaceB, but currently autowired object as InterfaceA is not a (sub)-type from MyClass.
if(myClass instanceof MyClass) {
InterfaceB myClassFromInterfaceB =(InterfaceB) myClass;
result= myClassFromInterfaceB.methodFromInterfaceB
}
How can I autowire one object in spring, which can call all methods from all interfaces, which will be implemented by this object?
It is only possible to declare two different objects ?
If the code may be changed, the cleanest way would be creating an interface that is composed of these two interfaces and making your implementation class derive from it.
Then you can declare your field to inject with this super interface as type :
#Autowired
InterfaceAandB myClass;
If the code cannot be changed, as alternative declare two fields to autowire in your bean and specify different interface types for each field.
It will result to a same object injected twice but referenced by two variable with different interfaces :
#Autowired
InterfaceA myA;
#Autowired
InterfaceB myB;

Using Singleton enum in Spring MVC

Here is my singlton class using enum:
public enum MyInstanceFactory {
INSTANCE;
private SOMEOBJECT;
private int countInitialization = 0;
private MyInstanceFactory(){
countInitialization++;
System.out.println("WOW!! This has been initialized: ["+countInitialization+"] times");
SOMEOBJECT = SOMETHING
}
public Session getSomeobject(){ return SOMEOBJECT; }
}
Now I am calling it like inside MVC controller
Session cqlSession = MyInstanceFactory.INSTANCE.getSomeobject();
In this way it calls constructer only first time and next and onwards it return the correct value for SOMEOBJECT.
My question is I want to do the same thing when a spring application start i.e. initializing contructor once and use **getSomeobject** multiple times.
I saw THIS SO ANSWER but here they are saying
If it finds a constructor with the right arguments, regardless of visibility, it will use reflection to set its constructor to be accessible.
Will reflection create problem for a singlton class?
If you need a non-subvertible singleton class (not just a singleton bean that's shared by many other beans, but actually a singleton class where the class can only ever be instantiated once), then the enum approach is a good one. Spring won't try to instantiate the enum itself, because that really makes no sense; that would be a much more extremely broken thing to do than merely calling a private constructor.
In that case, to refer to the enum instance from Spring configuration, you do the same thing as for any other static constant; for example:
<util:constant static-field="MyInstanceFactory.INSTANCE" />

How do I get a property value from an ApplicationContext object? (not using an annotation)

If I have:
#Autowired private ApplicationContext ctx;
I can get beans and resources by using one of the the getBean methods. However, I can't figure out how to get property values.
Obviously, I can create a new bean which has an #Value property like:
private #Value("${someProp}") String somePropValue;
What method do I call on the ApplicationContext object to get that value without autowiring a bean?
I usually use the #Value, but there is a situation where the SPeL expression needs to be dynamic, so I can't just use an annotation.
In the case where SPeL expression needs to be dynamic, get the property value manually:
somePropValue = ctx.getEnvironment().getProperty("someProp");
If you are stuck on Spring pre 3.1, you can use
somePropValue = ctx.getBeanFactory().resolveEmbeddedValue("${someProp}");
Assuming that the ${someProp} property comes from a PropertyPlaceHolderConfigurer, that makes things difficult. The PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor and as such only available at container startup time. So the properties are not available to a bean at runtime.
A solution would be to create some sort of a value holder bean that you initialize with the property / properties you need.
#Component
public class PropertyHolder{
#Value("${props.foo}") private String foo;
#Value("${props.bar}") private String bar;
// + getter methods
}
Now inject this PropertyHolder wherever you need the properties and access the properties through the getter methods

Resources