Spring #Autowired not working for eagerly initialized beans - java

I am trying to write a service-oriented application.
I have a been called memory defined as such:
package com.example.assets;
//imports ignored
#Resource
public class Memory {
}
And I have a service been called memoryHandler defined as such:
package com.example.service;
//imports ignored
#Service
public class MemoryHandler {
#Autowired
private Memory memory;
public void execute() {
//do something with memory
}
}
There is also another class, which is a BeanFactoryPostProcessor:
package com.example.service;
//imports ignored
#Component
public class PostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.getBeansOfType(MemoryHandler.class, false, true);
}
}
Which prematurely looks up the bean, memoryHandler, leaving it instantiated` but not autowired. However, I want the bean to be autowired before it is fetched by the factory.
In my Main class I have written:
package com.example.service;
//imports ignored
public class Main {
public static void main(String[] args) {
final ApplicationContext context = new ClassPathXmlApplicationContext("/context.xml");
context.getBean(MemoryHandler.class).execute();
}
}
I get a NullPointerException on the line I work with the memory. I replaced the above declaration with a setter injection, and upon tracing realized that the injection never occurs.
I have changed the annotations on both components to Service, Repository, and Component and also have tried replacing Autowired with Resource to no avail.
What am I missing here? I have read all the questions that have shown up in my search for an answer, and none of them helps me (I got the tip about using Resouce annotations there).
Needless to say, I have not missed annotation configuration for my beans:
<context:annotation-config/>
<context:component-scan base-package="com.example"/>
Moreover, autowiring works just fine when autowired beans are defined in the XML configuration file, and not via annotations.
I am using Spring 3.2.3.RELEASE.

Changing the implementation of the PostProcessor is the key:
Instead of:
public class PostProcessor implements BeanFactoryPostProcessor {
I will have to write:
public class PostProcessor implements ApplicationContextAware {
This ensures that the context will be fully populated before it is post-processed, which in my case works just fine. But I am wondering if there is another way to do this, using the usual BeanFactoryPostProcessor interface?

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.

NoSuchBeanDefinitionException: No qualifying bean of type available: expected at least 1 bean which qualifies as autowire candidate

I am trying to migrate a Spring 4.x.x to Spring boot and it has a dependency on a class in external spring 2.5 jar. I have made all the autowiring changes and below is my application class
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages = { "com.xyz" })
public class MainApiApplication {
public static void main(String[] args) {
SpringApplication.run(MainApiApplication.class, args);
}
}
The dependent class in the external jar is present under the package com.xyz.abc because of which I have placed my main application class under com.xyz package and also added the component scan under the same package
Here are my component classes with the dependency autowired
#Component
public class ComponentClassA {
#Autowired
private ComponentClassB currencyService;
}
#Component
public class ComponentClassB {
#Autowired
private DependentClass depClass;
}
DependentClass is the class present in the external dependent jar which I have locally attached and built
When building the application, compilation of all files is fine and build is generated successfully. But when I start the application, I get the below error
Field DependentClass in com.xyz.ComponentClassB required a bean of type 'com.xyz.common.util.DependentClass' that could not be found.
I don't understand the reason for the class from external jar being not found as I have added component scan for the package
The definition of DependentClass is like below
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}
Is it because DependentClass is extending a class ? Can someone help me figure out the reason for the error ?
The DependentClass does not have #Component annotation on it. So, you need to create a bean of DependentClass yourself either via XML or Java config.
And it is not necessary that you place your main class under the same package as DependentClass.
Define your class as per below:-
#Component("depClass")
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}
Component register it into your context defination if this package lie into your ScanBasePackages and the depClass inside the component annotation define the name of your bean.
you can also call it by:-
#Autowired
#Qualifier("depClass")
private DependentClass dependentClass;
If that class define in your external class then use #Bean annotaion like:-
#Bean
public DependentClass depClass(){
return new DependentClass();
}
After that Autowired the class you get the instance finally.
DependentClass is not defined in your current Spring Context.DependentClass is not annotated with a bean (#Bean).Hence nosuchbeandefinitionexception occurs.
#Bean
public class DependentClass extends ResourceClass<Map<String, Double>> {
// Methods and logic
}

Why #PostConstruct method is not called when autowiring prototype bean with constructor argument

I have a prototype-scope bean, which I want to be injected by #Autowired annotation. In this bean, there is also #PostConstruct method which is not called by Spring and I don't understand why.
My bean definition:
package somepackage;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
#Scope("prototype")
public class SomeBean {
public SomeBean(String arg) {
System.out.println("Constructor called, arg: " + arg);
}
#PostConstruct
private void init() {
System.out.println("Post construct called");
}
}
JUnit class where I want to inject bean:
package somepackage;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#ContextConfiguration("classpath*:applicationContext-test.xml")
public class SomeBeanTest {
#Autowired
ApplicationContext ctx;
#Autowired
#Value("1")
private SomeBean someBean;
private SomeBean someBean2;
#Before
public void setUp() throws Exception {
someBean2 = ctx.getBean(SomeBean.class, "2");
}
#Test
public void test() {
System.out.println("test");
}
}
Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="somepackage"/>
</beans>
The output from execution:
Constructor called, arg: 1
Constructor called, arg: 2
Post construct called
test
When I initialize bean by calling getBean from ApplicationContext everything works as expected. My question is why injecting bean by #Autowire and #Value combination is not calling #PostConstruct method
Why is #Value used instead of #Autowired?
The #Value annotation is used to inject values and normally has as destination strings, primitives, boxed types and java collections.
Acording to Spring's documentation:
The #Value annotation can be placed on fields, methods and method/constructor parameters to specify a default value.
Value receives a string expression which is used by spring to handle the conversion to the destination object. This conversion can be through the Spring's type conversion, the java bean property editor, and the Spring's SpEL expresions. The resulting object of this conversion, in principle, is not managed by spring (even though you can return an already managed bean from any of this methods).
By the other hand, the AutowiredAnnotationBeanPostProcessor is a
BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary config methods. Such members to be injected are detected through a Java 5 annotation: by default, Spring's #Autowired and #Value annotations.
This class handles the field injection, resolves the dependencies, and eventually calls the method doResolveDependency, is in this method where the 'priority' of the injection is resolved, springs checks if a sugested value is present which is normally an expression string, this sugested value is the content of the annotation Value, so in case is present a call to the class SimpleTypeConverter is made, otherwise spring looks for candicate beans and resolves the autowire.
Simply the reason #Autowired is ignored and #Value is used, is because the injection strategy of value is checked first. Obviously always has to be a priority, spring could also throw an exception when multiple conflicting annotations are used, but in this case is determined by that previous check to the sugested value.
I couldn't find anything related to this 'priority' is spring, but simple is because is not intended to use this annotations together, just as for instance, its not intended to use #Autowired and #Resource together either.
Why does #Value creates a new intance of the object
Previously I said that the class SimpleTypeConverter was called when the suggested value was present, the specific call is to the method convertIfNecessary, this is the one that performs the conversion of the string into the destination object, again this can be done with property editor or a custom converter, but none of those are used here. A SpEL expression isn't used either, just a string literal.
Spring checks first if the destination object is a string, or a collection/array (can convert e.g. comma delimited list), then checks if the destination is an enum, if it is, it tries to convert the string, if is not, and is not an interface but a class, it checks the existance of a Constructor(String) to finally create the object (not managed by spring). Basically this converter tries many different ways to convert the string to the final object.
This instantiation will only work using a string as argument, if you use for instance, a SpEL expression to return a long #Value("#{2L}"), and use an object with a Constructor(Long) it will throw an IllegalStateException with a similar message:
Cannot convert value of type 'java.lang.Long' to required type 'com.fiberg.test.springboot.object.Hut': no matching editors or conversion strategy found
Possible Solution
Using a simple #Configuration class as a supplier.
public class MyBean {
public MyBean(String myArg) { /* ... */ }
// ...
#PostConstruct public init() { /* ... */ }
}
#Configuration
public class MyBeanSupplier {
#Lazy
#Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode = ScopedProxyMode.NO)
public MyBean getMyBean(String myArg) {
return new MyBean(myArg);
}
}
You could define MyBean as a static class in MyBeanSupplier class if its the only method it would have. Also you cannot use the proxy mode ScopedProxyMode.TARGET_CLASS, because you'll need to provide the arguments as beans and the arguments passed to getMyBean would be ignored.
With this approach you wouldn't be able to autowire the bean itself, but instead, you would autowire the supplier and then call the get method.
// ...
public class SomeBeanTest {
#Autowired private MyBeanSupplier supplier;
// ...
public void setUp() throws Exception {
someBean = supplier.getMyBean("2");
}
}
You can also create the bean using the application context.
someBean = ctx.getBean(SomeBean.class, "2");
And the #PostConstruct method should be called no matter which one you use, but #PreDestroy is not called in prototype beans.
I read through the debug logs and stack trace for both scenarios many times and my observations are as follows:-
When it goes to create the bean in case of #Autowire, it basically ends up injecting value to the constructor via using some converters. See screenshot below:-
The #Autowire is ineffective. So, in your code, if you even remove #Autowired it will still work. Hence, supporting #1 when #Value is used on property it basically created the Object.
Solution:-
You should be having a bean with name arg injected with whatever value you want. E.g. I preferred using configuration class(you could create the bean in context file) and did below:-
#Configuration
public class Configurations {
#Bean
public String arg() {
return "20";
}
}
Then test class would be as below (Note you could use change ContextConfiguration to use classpath to read context file ):-
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SomeBean.class, Configurations.class})
public class SomeBeanTest {
#Autowired
ApplicationContext ctx;
#Autowired
String arg;
#Autowired
private SomeBean someBean;
private SomeBean someBean2;
#Before
public void setUp() throws Exception {
someBean2 = ctx.getBean(SomeBean.class, "2");
}
#Test
public void test() {
System.out.println("\n\n\n\ntest" + someBean.getName());
}
}
So, a learning for me as well to be careful with the usage of #Value as it could be misleading that it helped in autowiring by injecting value from some spring bean that got created in the background and could make applications misbehave.
When you run the test, a new bean for the test is created (i.e. not the SomeBean class, the SomeBeanTest class). #Value will be instantiated as a member value (not a bean) and thus default BeanPostProcessor (AutowiredAnnotationBeanPostProcessor) will not attempt initializing it.
To show that I have moved your System.out.println() to log.info() (keep lines in sync). Enabling debug-level logging shows:
DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'somepackage.SomeBeanTest': AutowiredFieldElement for org.springframework.context.ApplicationContext somepackage.SomeBeanTest.ctx
DEBUG org.springframework.core.annotation.AnnotationUtils - Failed to meta-introspect annotation [interface org.springframework.beans.factory.annotation.Autowired]: java.lang.NullPointerException
DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'somepackage.SomeBeanTest' to bean named 'org.springframework.context.support.GenericApplicationContext#39c0f4a'
DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected element of bean 'somepackage.SomeBeanTest': AutowiredFieldElement for private somepackage.SomeBean somepackage.SomeBeanTest.someBean
DEBUG org.springframework.core.annotation.AnnotationUtils - Failed to meta-introspect annotation [interface org.springframework.beans.factory.annotation.Value]: java.lang.NullPointerException
DEBUG org.springframework.beans.BeanUtils - No property editor [somepackage.SomeBeanEditor] found for type somepackage.SomeBean according to 'Editor' suffix convention
INFO somepackage.SomeBean - Constructor called, arg: 0
DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test method: ....
INFO somepackage.SomeBeanTest - test
DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method:
A way to workaround that works is to initialize the bean manually:
#Value("0")
private SomeBean someBean;
#PostConstruct
private void customInit() {
log.info("Custom Init method called");
someBean.init();
}
Which will produce:
INFO somepackage.SomeBean - Constructor called, arg: 0
INFO somepackage.SomeBeanTest - Custom Init method called
INFO somepackage.SomeBean - Post construct called
INFO somepackage.SomeBeanTest - test
#Value does not do what you are expecting it to do. It cannot be used to supply a constructor arg to the bean being created.
See this SO Q&A: Spring Java Config: how do you create a prototype-scoped #Bean with runtime arguments?
If I am not wrong :-
Spring RULE
Field injection happens after objects are constructed since obviously the container cannot set a property of something which doesn't exist. The field will be always unset in the constructor.
You are trying to print the injected value (or do some real initialization :)),
Using PostConstruct:-
in your code you have two beans.
1 SomeBean after constructor called the filed value is set .
2 SomeBean2 you are passing arg as value 2 that have been set in second bean
you can use a method annotated with #PostConstruct, which will be executed after the injection process.
#RunWith(SpringRunner.class)
#ContextConfiguration("classpath*:applicationContext-test.xml")
public class SomeBeanTest {
#Autowired
ApplicationContext ctx;
#Autowired
#Value("1")
private SomeBean someBean;
private SomeBean someBean2;
#Before
public void setUp() throws Exception {
someBean2 = ctx.getBean(SomeBean.class, "2");
}
#Test
public void test() {
System.out.println("test");
}
}

Better way to register beans in Spring

I am new in Spring. I understand process of Dependency Injection and Inversion Of Control as well. But in few days ago I found one source code which compel me thinking about it.
If I am not wrong, Beans can be registered by Stereotype annotations - #Component, #Service, etc.
In code which I found will be defined class with some logic, but without annotation. Next that same class will be initialized in some #Configuration class as been like that:
#Bean
public Foo fooBean() {
return new Foo();
}
Can you tell me what is different between these options and when they use? Thanks in advice.
The greatest benefit of #Configuration and #Bean is that allows you to create spring beans that are not decorated with #Component or any of its children (#Service, #Repository and those). This is really helpful when you want/need to define spring beans that are defined in an external library that has no direct interaction with Spring (maybe written by you or somebody else).
E.g.
You have a jar created by an external provider that contains this class:
public class EmailSender {
private String config1;
private String config2;
//and on...
public void sendEmail(String from, String to, String title, String body, File[] attachments) {
/* implementation */
}
}
Since the class is in an external jar, you cannot modify it. Still, Spring allows you to create spring beans based on this class (remember, the bean is the object, not the class).
In your project, you'll have something like this:
import thepackage.from.externaljar.EmailSender;
#Configuration
public class EmailSenderConfiguration {
#Bean
public EmailSender emailSender() {
EmailSender emailSender = new EmailSender();
emailSender.setConfig1(...);
emailSender.setConfig2(...);
//and on...
return emailSender;
}
}
And then you can inject the bean as needed:
#Service
public class MyService {
#Autowired
private EmailSender emailSender;
}
#Configuration is used to define your configuration of your application. In the end #Bean, #Service, #Component will all register a bean, but using #Configuration with all beans (services, components) defined in a single place makes your app more organized and easier to troubleshoot.

Spring #Transactional not proxying when referenced on xml

I am working on some legacy code that uses spring bean definitions on xml.
The module I am building uses annotations.
The problem is that sometimes I need to override a legacy bean definition so I need to put my beans on xml as well.
I have the following:
public class BeanIAmOverriding {
private MyAnnotatedBean bean;
}
#Component
public class MyAnnotatedBean {
private Repository repo;
}
#Repository
public class Repository {
#Transational
public Something find(...)
}
Xml file:
<bean id="bean" class="a.b.c.BeanIAmOverriding"/>
In this scenario, my repository does NOT get proxied with the transactional aspec.
I even tried just aliasing it but the same thing happens.
My current workaround is implementind BeanFactoryAware.
Do you have any better ideas?
EDIT:
Let me clarify.
I do know dependency injection, I just ommited some configuration I didn't think would be that relevant given the context, but here they are.
I would like to do something like:
<bean id="bean" class="a.b.c.BeanIAmOverriding">
<constructor-arg index="0" ref="myAnnotatedBean"/>
</bean>
That doesn't work. When I do that my Repository does not get proxied by the transactional aspect.
So I have this workaround:
public class BeanIAmOverriding implements BeanFactoryAware{
//private MyAnnotatedBean bean;
private BeanFactory beanFactory;
public void something(){
beanFactory.getBean(MyAnnotatedBean.class).doSomething();
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
Like I said in my comment, the problem is that you're not injecting the 'BeanIAmOverriding.bean', as spring doesn't know it has to inject it! Try the following (I'm not 100% sure if the following will work, as it's been a long time since I worked on a project that used a mix of 'legacy' xml and annotations).
public class BeanIAmOverriding {
private MyAnnotatedBean bean;
#Autowired
public BeanIAmOverriding(MyAnnotatedBean bean) {
this.bean = bean;
}
}
The #Autowired annotation will tell spring how to instantiate the class. Spring will then take the instance of MyAnnotatedBean and inject it in the constructor.
I'm not sure how experienced you are with Spring, but I would recommend you to read a bit the section on dependency injection.

Categories