Bean autowire fail when running tests only - java

Hopefully someone might have the answer for this problem.
I have a autowire problem occuring when I run my tests but not else.
The exception is pretty clear as it says 'myField' is missing. The field is however inherited from a base class. I cannot find the answer to my problem anywhere so I will try my luck here.
The exception
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myService': Injection of autowired dependencies failed;
nested exception is java.lang.NoSuchFieldError: myField
My base class
public abstract class CommonStuff {
protected String myField; // the one thats gone missing
public abstract void setMyField(String myField);
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
public void setMyField(String myField) {
this.myField = myField;
}
...
}
My controller
#Controller
public class MyController {
#Autowired
private MyService myService;
public void setMyService(MyService myService) {
this.myService = myService;
}
...
}
My application-context.xml
Nothing seems to be left out.
<context:component-scan base-package="com.myapp" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:my.properties</value>
<value>classpath:myother.properties</value>
</list>
</property>
</bean>
my.properties
myProperty.myField=some value
My test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:application-context.xml" })
public class MyControllerTest {
#Autowired
MyController myController;
#Mock
MyService myService;
#Test
public void myServiceTest() {
// do stuff with myService
}
...
}
The problem
As I mentioned the code runs fine but a spring has trouble autowiring whenever I try to run the test.
The problem is not the test but the wiring when starting the test. Somehow spring cannot find myField from the abstract CommonStuff class so it says that MyService do not have the field.
If needed I can post the full stacktrace but I think the essense of the exception is already here.

I gave up and moved the myField back into the service and skipped the setMyField.
This is how it is now.
Base class
public abstract class CommonStuff {
public abstract String getMyField();
public void doCommonStuff() {
// use getMyField()
}
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
private String myField;
#Override
public String getMyField() {
return myField;
}
...
}
This solves what I wanted since I now have access to myField from CommonStuff.

Related

#Autowired field is null when used in new abstract class

I have a bit of code that is working :
#Component
public class MessageUtil {
#Autowired
#Qualifier("processMessages")
private ReloadableConfig config;
public String createMessage() {
return config.getPropertyStr("message.simple.signature");
}
}
The bean processMessages is defined here :
<bean id="processMessages" class="com.company.framework.resources.ReloadableConfig">
<property name="basename" value="classpath:com/company/aaa/bbb/domain/service/processMessages"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="cacheSeconds" value="60"/>
</bean>
Then I created some new classes :
public abstract class MessageBuilder {
#Autowired
#Qualifier("processMessages")
protected ReloadableConfig config;
public abstract String createMessage();
}
#Component
public class SimpleMessageBuilder extends MessageBuilder {
private String template;
private void setTemplate() {
template = config.getPropertyStr("message.simple.signature");
}
#Override
public String createMessage() {
setTemplate();
return template;
}
}
I now have a NullPointerException because in setTemplate(), config is null.
What's the problem in the second code ?
#Autowired doesn't work neither on field neither on constructors of abstract classes. It works on setter of abstract class but be sure to make it final because if overwritten by concrete class behavior is unstable. An abstract class isn't component-scanned since it can't be instantiated without a concrete subclass.

Why #Autowired didn't work in static method

I found many solutions to this issue, and choose the below one.
But it still gets NullpointerException, what's wrong?
A Class
#Component
public class A {
private static Foo foo;
#Autowired
public void setFoo(Foo foo) {
A.foo = foo;
}
public static someFunction() {
foo.doSomething();
}
}
B Class
#Service
public class B {
public void someFunction() {
A.someFunction();
}
}
You cannot auto-wire static properties in Spring, Static fields are instantiated during class load as they are the properties of the class while auto wired attributes work after spring initializes the beans.
Although you may use MethodInvokingFactoryBeanin Spring to achieve what you wanted.
some example would be in XML as below
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
<property name="arguments">
<list>
<ref bean="theProperty"/>
</list>
</property>
</bean>
Edit :- without XML
inside your #Configuration class
do
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("MyClass.staticMethod");
return methodInvokingFactoryBean;
}
let me know in case you need more help.

How to define which bean to autowire in Spring

I have 2 beans of the same type:
#Component("beanA")
public class BeanA implements BaseBean {}
#Component("beanB")
public class BeanB implements BaseBean {}
This type is used in my service:
#Service
public class MyService {
#Autowired
private BaseBean baseBean;
}
Now I want to use both possible MyService beans in another service
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}
How can I achieve that? Maybe I should take another approach?
I know how to do it in XML-based beans configuration. How can I do it using annotations?
<bean id="AnotherService" class="AnotherService">
<property name="myServiceWithBeanA" ref="myServiceWithBeanA" />
<property name="myServiceWithBeanB" ref="myServiceWithBeanB" />
</bean>
<bean id="myServiceWithBeanA" class="MyService">
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<property name="baseBean" ref="beanB" />
</bean>
<bean id="beanA" class="BeanA" />
<bean id="beanB" class="BeanB" />
The problem is that MyService is annotated with #Service. This means that it is a singleton - only one instance will be created.
In order to create multiple instances, you need to expose two #Beans via configuration.
#Configuration
public class MyServiceConfig {
#Bean
public MyService serviceA(#Qualifier("beanA") beanA) {
return new MyService(beanA);
}
#Bean
public MyService serviceB(#Qualifier("beanB") beanB) {
return new MyService(beanB);
}
}
MyService would become
public class MyService {
private BaseBean baseBean;
public MyService(BaseBean baseBean) {
this.baseBean = baseBean;
}
}
You can then pass all of these to the other service with qualifiers
#Service
public class AnotherService {
#Autowired
#Qualifier("serviceA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("serviceB")
private MyService myServiceWithBeanB;
}
Using the #Qualifier annotation you can specify which bean you want to autowire.
#Service
public class AnotherService {
#Autowired
#Qualifier("beanA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("beanB")
private MyService myServiceWithBeanB;
}
Hope this helps.
In your xml bean definition add the these tags <qualifier value="name"/>.
<bean id="myServiceWithBeanA" class="MyService">
<qualifier value="A"/>
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<qualifier value="B"/>
<property name="baseBean" ref="beanB" />
</bean>
And then you can get them by using Qualifier annotation like this:
#Autowired
#Qualifier("A")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("B")
private MyService myServiceWithBeanB;
You also can do more stuff than that.
Have a look at the documentation on the following link:
Qualifier documentaiton
Not everything can be done with annotations. In cases where you need to create multiple instance of a bean but with different arguments you have to fallback to #Configuration and define those beans as you would in the XML config.
#Configuration
public class AppConfig {
#Bean
public MyService myServiceWithBeanA(BeanA beanA) {
return new MyService(beanA);
}
#Bean
public MyService myserviceWithBeanB(BeanB beanB) {
return new MyService(beanB);
}
}
Now just tell AnotherService to expect MyService twice with matching bean names as name of the bean defining method is its default qualifier.
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}

Invalid property of bean class is not writable or an invalid setter method

This may looks like a duplicate of this question. But this is different.
I was trying to refactor my legacy code by using method injection in spring.
I have a bean class which contains many static helper methods. My targeted method as follows:
Context.java
private static MessageSender messageSender;
//...
public static MessageSender getMessageSender(){
return messageSender;
}
Context bean
<bean id="context" class="org.abc.Context">
<property name="messageSender"><ref bean="mailMessageSender"/></property>
</bean>
MailMessageSender.java
public abstract class MailMessageSender{
protected abstract Session createSession();
//using createSession() somewhere in this class
}
MailMessageSender bean
<bean id="session" class="javax.mail.Session" scope="prototype" />
<bean id="mailMessageSender" class="org.abc.MailMessageSender">
<lookup-method name="createSession" bean="session"/>
</bean>
I'm getting invalid property error when I'm installing the project.
You can't inject static field, change your variable in Context.java become like this:
private MessageSender messageSender;
//...
public MessageSender getMessageSender(){
return messageSender;
}

Can I inject an interface subtype in Spring?

It doesn't seem to be working right now. I get a
java.lang.NullPointerException
I have a class that implements an interface
public class LearnerDao implements BaseDao {
private BaseDao dao;
public void setDao(BaseDao dao) {
this.dao=dao;
}
.
.
.
}
This is my wiring
<bean id="pm" factory-bean="pmf" factory-method="getPersistenceManager"
scope="prototype"></bean>
<bean id="learnerDao" class="com.hardwire.dao.impl.LearnerDao">
<property name="pm" ref="pm"></property>
</bean>
<bean id="twitterUserDao" class="com.hardwire.dao.impl.TwitterUserDao">
<property name="pm" ref="pm"></property>
</bean>
<bean id="learnerService" class="com.hardwire.service.LearnerService">
<property name="dao" ref="learnerDao"></property
</bean>
Here's my learnerService
public class LearnerService {
private static final Logger log =
Logger.getLogger(LearnerService.class.getName());
private BaseDao dao;
.
.
.
public void insert(Learner learner){
if (dao==null){
log.info("dao is null");
}
else {
log.info("dao is not null");
}
dao.insert(learner);
}
public void setDao(BaseDao dao) {
this.dao = dao;
}
It's only learnerDao that implements BaseDao. On the other hand, bean twitterUserDao does not. I'd like to note that twitterUserDao was injected just okay but learnerDao wasn't.
The logs show that learnerDao is null. So I was wondering if this had anything to do with learnerDao implementing an inteface.
Nope, you can definitely do that. Note that you're trying to set a pm property in learnerDao, but you haven't shown anything setting the dao property. Could that be the problem?
I finally found where everything's going wrong. I had this bug of code to kill in a Controller that has learnerService as its dependency:
learnerService = new LearnerService();
Laughing my ass off right now! :))

Categories