I read, that in XML-based Spring configuration beans can inherit factory method.
I tried to implement it:
Controller interface:
public interface Controller {
String method();
}
ControllerFactory class:
public class ControllerFactory {
public Controller getController(String controllerName){
switch(controllerName){
case "OtherController":
return new OtherController();
case "SampleController":
return new SampleController();
default:
throw new IllegalArgumentException("Wrong controller name.");
}
}
}
SampleController implementation:
public class SampleController implements Controller {
#Override
public String method() {
return "SampleController";
}
}
OtherController implementation:
public class OtherController implements Controller {
#Override
public String method() {
return "OtherController";
}
}
But the following XML configuration:
<!--factory method inheritance -->
<bean id="controllerFactory" class="factory.ControllerFactory"/>
<bean id="parentController" abstract="true" factory-bean="controllerFactory" factory-method="getController"/>
<bean id="otherController" parent="parentController">
<constructor-arg index="0" value="OtherController"/>
</bean>
Gives compile-time error:
No matching constructor found in class 'Controller'
How can I change it to have factory method bean inheritance implemented properly?
Copying factory-method configuration to child bean works as expected:
<bean id="otherController" parent="parentController" factory-bean="controllerFactory" factory-method="getController">
<constructor-arg index="0" value="OtherController"/>
</bean>
Change bean with id parentController as follows:
<bean id="parentController" class="factory.ControllerFactory" factory-bean="controllerFactory" factory-method="getController">
<constructor-arg index="0" value="OtherController"/>
</bean>.
Try this it may work.
Related
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;
}
consider the following code:
public abstract class MachineInPitImpl extends AbstractPersistentObject implements MachineInPit {
protected PersonReference currentOperatorRef;
public void setCurrentOperatorRef(PersonReference currentOperatorRef) {
this.currentOperatorRef = currentOperatorRef;
this.currentOperatorObj = null;
}
public PersonReference getCurrentOperatorRef() {
return currentOperatorRef;
}
The above class is not wired with spring context, I need to extend this class and grab the values in the get method of this class in my new class.
I have wrote a class as this:
public class MachineOPJMXBeanImpl extends MachineInPitImpl {
public MachineOPJMXBeanImpl(){
}
#Override
public PersonReference getCurrentOperatorRef() {
return super.getCurrentOperatorRef();
}
}
But the value in this class get method is null.Why am I getting null value?
Here is the applicationcontext.xml file:
<bean id="machineOPJMXBean"
class="com.mincom.works.cc.personnel.node.MachineOPJMXBeanImpl" parent="machineInPitImpl">
<property name="currentOperatorRef" ref="currentOperatorRef"/>
</bean>
<bean id="machineInPitImpl" class="minestar.pitlink.domain.pitmodel.MachineInPitImpl" abstract="true" scope="singleton" lazy-init="true">
<property name="currentOperatorRef" ref="currentOperatorRef"/>
</bean>
<bean id="currentOperatorRef" class="minestar.machinetracking.domain.PersonReference"/>
applicationContext
<bean id="contentRegisteringBean" parent="abstractRegisteringBean" lazy-init="false">
<property name="processor">
<bean class="com.somepackage.ContentService$Processor"/>
</property>
</bean>
<bean id="abstractRegisteringBean" class="test.spring.MockFactoryBean">
<property name="type" value="com.somepackage.ProcessorRegisteringBeanImpl"/>
</bean>
ProcessorRegisteringBeanImpl
public class ProcessorRegisteringBeanImpl {
private Processor mProcessor;
public Processor getProcessor() {
return mProcessor;
}
public void setProcessor(final Processor processor) {
mProcessor = processor;
}
}
MockFactoryBean.java
public class MockFactoryBean<T> implements FactoryBean<T> {
private Class<T> type;
public void setType(Class<T> type) {
this.type = type;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(type);
}
#Override
public Class<T> getObjectType() {
return type;
}
#Override
public boolean isSingleton() {
return true;
}
}
Exception:
org.springframework.beans.NotWritablePropertyException: Invalid
property 'processor' of bean class
[test.spring.MockFactoryBean]: Bean property 'processor' is
not writable or has an invalid setter method. Does the parameter type
of the setter match the return type of the getter?
When you declare a FactoryBean, Spring expects that you configure properties of the FactoryBean rather than properties of the object it creates.
Try the following instead:
<bean id="contentRegisteringBean" parent="abstractRegisteringBean" lazy-init="false">
<!-- Define concrete class to pass to Mockito.mock() -->
<constructor-arg value = "com.somepackage.ProcessorRegisteringBeanImpl" />
<property name="processor">
<bean class="com.somepackage.ContentService$Processor"/>
</property>
</bean>
<!-- Abstract definition of beans created using Mockito.mock() -->
<bean id="abstractRegisteringBean" abstract = "true"
class="org.mockito.Mockito" factory-method = "mock">
</bean>
I currently have the following Spring bean definitions:
<bean id="myAwesomeBeanSetup" class="com.beanpckg.SuperBean" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean" class="com.beanpckg.SuperBean" scope="prototype" depends-on="myAwesomeBeanSetup"/>
Essentially, what I need is to run SuperBean.doPreStep only once, but still have a fresh instance of SuperBean for subsequent calls. Since I have a lot of beans with such structure, I was wondering, is there a more elegant way to achieve this without having two lines of definitions? Note that there could also be "cross-bean" dependencies, for example:
<bean id="myAwesomeBeanSetup" class="com.beanpckg.SuperBean" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean2Setup" class="com.beanpckg.SuperBean2" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean" class="com.beanpckg.SuperBean" scope="prototype" depends-on="myAwesomeBeanSetup,myAwesomeBean2Setup"/>
You can put your code in the static initialization block as following:
public class SuperBean {
// …
static {
doPreStep();
}
public static void doPreStep() {
}
}
Alternatively, if you want a pure Spring solution, you can implement a FactoryBean and invoke the doPreStep() in its init method as following:
public class SuperFactoryBean implements FactoryBean<SuperBean>{
public void init() {
SuperBean.doPreStep();
}
public boolean isSingleton() {
return false;
}
public SuperBean getObject(){
return new SuperBean();
}
public Class<SuperBean> getObjectType() {
return SuperBean.class ;
}
}
And define your bean as following:
<bean id="myAwesomeBean" class="com.beanpckg.SuperFactoryBean" init-method="init">
</bean>
Depending what you want to achieve within your awesome superclass:
For me this would be the perfect usecase of having a separate singleton with the common code and autowire it into your prototype.
Since your init will not be different per bean why having it in a superclass?
How would I specify an anonymous inner bean in a named Spring Service?
#Service("myNamedService")
public class myNamedServiceClass {
private InnerBeanType innerBean;
#Autowired
public void setInnerBean(InnerBeanType innerBean) {
this.innerBean = innerBean;
}
}
I'm basically trying to achieve the equivalent of the following Spring XML wiring:
<bean name="myNamedService" class="somePackage.myNamedServiceClass">
<property name="innerBean">
<bean class="somePackage.InnerBeanType"/>
</property>
</bean>
Equivalent using pure annotations is I think not possible. You can use #Configuration though if the purpose is to not expose innerBean as a visible bean this way:
#Bean
public MyNamedServiceBean myNamedServiceBean(){
MyNamedServiceClass myNamedServiceBean = new MyNamedServiceClass();
myNamedServiceBean.setInnerBean(new InnerBeanType());
return myNamedServiceBean;
}