I've implemented a factory bean in Spring to instantiate different subclasses of a superclass. The problem I have is that superclass properties aren't being @Autowired
(I guess due to the new
command in the factory methods). This is my code:
@Component
public class ConfigBeanImpl implements ConfigBean{
@Override
public String expandParam(String param) {
return String.format("expanded %s", param);
}
}
public abstract class FactoryBean {
@Autowired
protected ConfigBean configBean;
private String property;
protected FactoryBean() {
this.property = configBean.expandParam("property");
}
public abstract String getProperty();
public static FactoryBean GET(int id) {
return new FactoryBeanGet(id);
}
public static FactoryBean POST(String param){
return new FactoryBeanPost(param);
}
}
public class FactoryBeanGet extends FactoryBean {
private int id;
protected FactoryBeanGet(int id) {
this.id = id;
}
@Override
public String getProperty() {
return Integer.toString(id);
}
}
public class FactoryBeanPost extends FactoryBean {
private String param;
protected FactoryBeanPost(String param) {
this.param = param;
}
@Override
public String getProperty() {
return param;
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
FactoryBean bean = (FactoryBean) context.getBean("factoryBeanGet", 12);
System.out.println(bean.getProperty());
bean = (FactoryBean) context.getBean("factoryBeanPost", "test param");
System.out.println(bean.getProperty());
}
}
And the applicationContext.xml:
<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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.spring" />
<bean id="factoryBeanGet" scope="prototype" class="com.spring.bean.FactoryBean"
factory-method="GET">
</bean>
<bean id="factoryBeanPost" scope="prototype" class="com.spring.bean.FactoryBean"
factory-method="POST">
</bean>
The protected ConfigBean configBean
property in abstract class FactoryBean
isn't being @Autowired
and hence is null
and the constructor throws a NullPointerException
. If I place it inside each of the subclasses, it works fine, but it'd be duplicated code. Is there a way to solve this or am I doing something wrong?
Put yourself in Spring's shoes. It must instantiate FactoryBean
, and then initialize its configBean
field. So, the first thing it will do is call the constructor. And then, once the object exists, it will initialize the object's field. It obviously can't initialize the field if the object doesn't exist yet. So, at the time the constructor is called, the field is still null.
Use constructor injection, or use a method annotated witb @PostConstruct
to call the configBean
.
That said, the private property
field that you're trying to initialize is not used anywhere, so you could as well remove it, and remove the configBean
field as well.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments