Spring #Autowired on a class new instance - java

I'm not so familiar with Spring and I have the following situation:
A repository class:
#Repository
public class MyRepository {
// ...
}
A class that uses the repository class:
public class MyClass extends AbstractClass {
#Autowired
private MyRepository myRepository;
//...
}
I know that if I annotate my MyClass with #Component and use it with an #Autowired, then the #Autowired MyRepository is resolved just fine.
Problem is I am in a situation that I need to create new instances of MyClass with reflection. So MyRepository is never resolved and is null all the time.
Is there a way to use #Autowired in this situation?
Explaining better my situation:
I have some implementations of AbstractClass.
In a setup phase of my application I create a HashMap of these implementations. Basically:
{"MyClass", MyClass.class}
//...
Then I have a generic Controller that maps to the url /{class}?options=...
Using the {class} #PathVariable, the HashMap above and reflection I am able to create a instance of a class based on the given options (this part is important). Do you guys think there's a better way of doing this?
Thanks in advance

Spring itself offers some functionality for doing auto-wiring in your objects
which you created by new or newInstance() or whatever.
To use it you need an AutowireCapableBeanFactory
which you get by Spring's normal dependency injection with #Autowired.
#Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
Then you use its autowireBean(Object) method
to inject the #Autowired properties into your bean.
Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);
Design note:
Think well if you really need the approach above.
The javadoc of AutowireCapableBeanFactory advises against using this interface for most use-cases:
This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactory or ListableBeanFactory for typical use cases.
Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example.

You can use Factory Design Pattern over here.
This might seem a little complicated in start but I am sure you will love it after you have implemented it.
Steps:
Add #Component on all implementations of AbstractClass.
Create a factory class as:
#Component
public class MyFactory {
private final Map<String, AbstractClass> impletationMap = new HashMap<>();
#Autowired
ApplicationContext context;
#PostConstruct
public void initialize() {
populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
}
private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
while (classIterator.hasNext()) {
AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
}
}
}
When the Bean of this MyFactory class is initialized, then it will lookup for all beans of type AbstractClass and put them in the HashMap(implementationMap).
Now from this factory you can get the HashMap and then get the implementations as and when you require. It will be very easy when you add new implementation of AbstractClass as factory will take care of it.

One work around is instead of binding the MyClass to the Hashmap to bind a Factory class. MyClassFactory. This way you will delegate the construction to a concrete factory that will do the job to instantiate the correct class and initialize the correct repository.
Here is an example:
{"MyClass", MyClassFactory.class}
The factory can be Component as well, then you need to bind the hashmap to the factory instance instead of the factory class. But lets say it is not a component:
//#Component this is optional
public MyClassFactory {
//#Autowired optional
ApplicationContext ctx;
public MyClass createInstance() {
MyRepository repo = ctx.getBean("")
MyClass myclass = new MyClass(repo)
return myclass;
}
}
If you mark it as component you can well also use ApplicationContextAware interface if you are going to autowire the ApplicationContext.

One approach is to declare #Component on top of MyClass.
Then, in the setup phase, you can pass the instance of MyClass instead of MyClass.class itself, in the HashMap. There won't be any need to create instances via reflection.
Note: You can fetch the instance of MyClass from your ApplicationContext in the setup phase.

Try this
#Component
public class SomeClass extends AbstractClass {
private static ApplicationContext applicationContext;
public MyClass getMyClass(){
// Now #Autowired MyRepository will work
return applicationContext.getBean(MyClass.class);
}
}

Yes, you can annotate all your AbstractClass implementation beans with #Component and use the next declaration
#Autowired
private List<AbstractClass> beans;
You can then convert that to a Map in a #PostConstruct method.
Spring won't complain about duplicate definitions if you autowire Lists.

Related

How to properly inject #Autowired between Spring Boot classes?

I have a classA which implements an interfaceA, with a methodA, then I have a classB in which I call classA with an #Autowired to be able to use methodA, but it gives me a warning that I must create a method for classA. Why is this happening? Doesn't #Autowired work like this in this case? Should I just instantiate classA? Thank you very much for your answers.
ClassA
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice springDataColminvoice;
#Override
public <S extends TransactionDto> S save(S s) {
Colm colm = transactionDataMapper.toEntity(s);
//methodA
springDataColminvoice.save(colm);
return null;
}
}
InterfaceA
public interface IRepository extends IRepository<TransactionDto, Integer> {}
ClassB
#Service
#RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService {
#Autowired
private RepositoryImpl repositoryImpl;
#Override
public void save(CMessage cMessage) throws HandlerException {
try {
TransactionDto transactionDto = cMessage.getTransaction();
// methodA
repositoryImpl.save(transactionDto);
} catch (Exception e) {
throw new HandlerException(e.getMessage());
}
}
}
Exception
Action:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.
(posting this as an answer since I do not have enough reputation to comment)
As others have pointed out already, a code sample would help tremendously.
That being said, though, it sounds like you're missing implementation for "ClassA".
If you have an interface that "ClassA" implements, you have to implement the interface's methods in "ClassA" before you can use them.
I assume your code currently looks somewhat like this?
public interface InterfaceA {
void methodA();
}
public class ClassA implements InterfaceA {
}
public class ClassB {
#Autowired
ClassA classA; // Cannot use {#link InterfaceA#methodA} because the class does not implement the function
}
If this is your code, make sure you add an implementation for your "methodA()" function in "ClassA". Somewhat like so:
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Additionally, in order to autowire in Spring (Boot), you need to ensure that the class you'd like to autowire is marked as such. You can autowire beans.
To make "ClassA" in the example eligible for autowiring, make sure to instantiate it either as:
A bean (using the #Bean annotation).
A component (using the #Component annotation).
A service (using the #Service annotation).
Any of the other annotations that may match your use case the best.
In our example, this would look somewhat like this:
#Component // Or #Service / whatever you may need
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Hope you've found any of this helpful. All the best!
-T
As what I have understood, #Autowire means injecting the value/instance of the specific property where you put the annotation #Autowire. In this case, #Autowire only happens when there is defined/created Bean within your basePackage of your Spring Boot project that can match it, i.e. where your #Autowire referred to (meaning there is no conflict issue like ambiguity, etc. and the DataType(Class) can be implicitly casted). In your example, first you treat the IRepository and/or RepositoryImpl as Repository without using the #Repository annotation to inform the Spring Boot default configuration that this is a Repository bean. As you didn't put the POM.xml or posted the related code, I presumed you are creating your own repository class. I think it's much better to post your dependencies here.
But as what others pointed out. You need to create a bean that can match the #Autowired you've put on TransactDataManager & SpringDataColminvoice. You need also to inform the Spring Boot or register it that your class A is a Bean by annotating
#Bean - defining a regular bean,
#Component - a Component in the Project,
#Service - a Service in the Project,
#Repository - a Repository (if you're using Spring JPA), etc.
#<Other Annotations depending of what other Spring Project/Dependencies your using>
Since newer versions of Spring is moving to annotation based from XML mapping, we need to put proper annotation for each class/object that we want to be auto injected/instantiated from #Autowired using the above sample annotations depending on the role/purpose of your class/object is.
I suggest if you're not sure. Then create a typical bean using common annotation #Bean. So your class A might be
#Component //Insert proper Annotation for your class if necessary. This is just a sample
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice
springDataColminvoice;//segunda
#Override
public <S extends TransactionDto> S save(S s) {
//Some implementation
}
#Bean
private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>){
return <an instance for TransactionDataManager>;
}
#Bean
private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>){
return <an instance for SpringDataColminvoice>;
}
}
Note that 2 beans definition are optional if there are already a Beans define on outside class or if it was marked by other annotation like #Service, #Component or other proper annotations and the other one bean is just a reference parameter for the other bean in order to properly instantiated.
In your class B is the following:
public class ClassB {
#Autowired
ClassA classA;
/*Note: ignore this Bean definition if Class A is annotated with #Component,
#Service, or other proper #Annotation for Class A.
*/
#Bean
private ClassA getClassA(<Some Parameters if Needed>){
return <Instance of Class A>
}
}
Take note that, you don't need to put a Bean definition inside the Class B if you put a proper annotation for your Class A like #Component, #Service, etc.

Spring App SonarQube Issue S3749

I am running into an issue with my Spring Applications and SonarQube. SQ is flagging both examples with "Annotate this member with "#Autowired", "#Resource", "#Inject", or "#Value", or remove it." on the instance variable mapLoadedByDatabaseCalls
Example 1:
#Service
public class Service implements InitializingBean {
#Autowired
private Dao dao;
private Map<Object, Object> mapLoadedByDatabaseCalls;
#Override
public void afterPropertiesSet() throws Exception {
mapLoadedByDatabaseCalls= new HashMap<>(Object.class);
....
}
}
Example 2:
#Service
public class Service {
#Autowired
private Dao dao;
private Map<Object, Object> mapLoadedByDatabaseCalls;
#PostConstruct
private void setMap() {
mapLoadedByDatabaseCalls= new HashMap<>(Object.class);
....
}
}
What is the correct way to instantiate variables after DI has completed?
A more generic solution to this that does not involve any additional annotations, is to initialize the offending variable in the class constructor.
public Service() {
mapLoadedByDatabaseCalls = new HashMap<>();
}
I believe that this is kludgy and that your original code is better, but this will eliminate the SonarQube complaint. Initialize your map in a #Bean, then reference that as #Autowired. Load the map with data in the #PostConstruct.
#Bean
public Map<Object, Object> getMapLoadedByDatabaseCalls() {
return new HashMap<>(Object.class);
}
#Autowired
private Map<Object, Object> mapLoadedByDatabaseCalls;
#PostConstruct
private void setMap() {
...
// load data into the map
mapLoadedByDatabaseCalls.put(key, value);
....
}
From the Spring Documentation > Initialization callbacks section
It is recommended that you do not use the InitializingBean interface
because it unnecessarily couples the code to Spring. Alternatively,
use the #PostConstruct annotation or specify a POJO initialization
method.
Essentially InitializingBean pre-existed in Spring before the JSR-250 support came on Spring 2.5 onwards (including the #PostConstruct annotation)
The rule S3749 describes that Spring #Component, #Controller, #Service, and #Repository classes are singletons by default, meaning only one instance of the class is ever instantiated in the application. Typically such a class might have a few static members, such as a logger, but all non-static members should be managed by Spring. That is, they should have one of these annotations: #Resource, #Inject, #Autowired or #Value.
Having non-injected members in one of these classes could indicate an attempt to manage state. Because they are singletons, such an attempt is almost guaranteed to eventually expose data from User1's session to User2.
Given the above details, Spring should be managing its all non-static members states. It all depends on the use case and should be avoided either using #Autoworied, class constructor or #PostConstruct.
SECURITY WARNING: OWASP A3:2017. This could leak sensitive data

DI & Autowiring vs instantiation in Spring [duplicate]

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Autowiring vs instantiating in Spring

I've started to use Spring recently. And I'm making spring mvc project. So my question is if it's preferred to make interfaces and autowire it with particular implementation by spring or just use class instances in case when I have only one implementation of that interface?
For example:
#Controller
public class MyController {
#Autowired
MyService myService;
#RequestMap("/")
public String mainPage() {
...
}
}
or
#Controller
public class MyController {
#RequestMap("/")
public String mainPage() {
MyService myService = new MyServiceImpl();
...
}
}
if there is only one implementation of MyService interface?
In most cases you should go with injection because:
It eases unit testing (you can inject mock or different implementation)
Spring can inject some dependencies into MyServiceImpl as well because it manages this object
You are not coupling your controller with particular implementation
Even if your service does not have an interface, because of the second reason you should consider injection.
The only case when you might want to skip Spring is when the class does not have any dependencies and is stateless. But most likely such a class is a utility that does not need any an instance at all because it has only static members.
It will depend on whether MyService is a bean that holds a state or not. If MyService does not hold state, then you don't need to create new instances and you can let Spring to inject it having the advantages above described

Application context bean

I am trying to extract the bean from application context.
so I defined class:
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext _applicationContext) throws BeansException {
applicationContext = _applicationContext;
}
}
and in my applicationContext.xml
<bean id="workflowService" class="com.mycompany.util.WorkflowService">
<bean id="applicationContextProvider" class="com.mycompany.util.ApplicationContextProvider"></bean>
<context:annotation-config />
However in my code when I try:
WorkflowService service = (WorkflowService) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
I get:
java.lang.ClassCastException: $Proxy40 cannot be cast to com.mycompany.util.WorkflowService
EDITED:
WorkflowService code:
public class WorkflowService implements Serializable {
...
#PostConstruct
public void init() {
}
...
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
I guess WorkflowService is a class implementing at least one interface (you haven't provided enough code). You are trying to lookup the exact class from Spring, while you should ask for one of the interfaces.
This is because Spring most of the time wraps beans in several proxies (e.g. transactional ones). If the class implements at least one interface, resulting proxy implements all of them, but cannot be cast into original class. If the class does not implement any interfaces (commonly considered a bad practice for heavyweight services, questionable though), Spring will use CGLIB subclassing from original class. In this case you code would be valid.
Your problem is this bit:
WorkflowService implements Serializable
Any proxies that Spring generates will implement all of the interfaces that your class does - in this case, Serializable, which is almost certainly not what you want.
What you should do is extract a new interface from WorkflowService, which includes the findData method (let's call it WorkflowOperations). By implementing that interface, you'll then be able to cast to that interface, e.g.
public interface WorkflowOperations {
Collection<lData> findData(Integer contractId);
}
public class WorkflowService implements WorkflowOperations {
...
#PostConstruct
public void init() {
}
...
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
and then:
WorkflowOperations service = (WorkflowOperations) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
You should probably also remove Serializable from WorkflowService. You almost certainly don't need this, it makes no sense to serialize Spring beans like this. If you just added Serializable out of habit, then remove it (and get out of that particular habit).
You are annotating your service with #Transactional, so Spring is wrapping your service bean with a transactional JDK dynamic proxy that implements the same interfaces as your bean, but is not a WorkflowService. That is why you get a ClassCastException when you try to assign it to a WorkflowService variable. I see two possible solutions:
Specify an interface WorkflowService with your business methods and implement it in a WorkflowServiceImpl class. Then in the Spring context change the bean definition from WorkflowService to WorkflowServiceImpl. This is what I recommend, both as a general design principle and specially to work in a Spring environment: Spring likes interfaces.
In your Spring context, add proxy-target-class="true" to your <tx:annotation-driven/> element in order to force Spring to implement proxies by subclassing, so that proxy instanceof WorkFlowService is true. I find this solution dirtier. Also note that you add a dependency on CGLIB this way.

Categories