Reputation: 1407
I have a small problem and I hope that there is some one who could review it and help me. I am using CGLib Mixin proxy to create a mixin of two interfaces / implementations. This mixin is used in my spring application. Everything works fine:
static InterfaceBoth createInstance() {
final Class<?>[] interfaces = new Class[] { InterfaceOne.class, InterfaceTwo.class, InterfaceBoth.class };
final Object[] delegates = new Object[] { new ClassOne(), new ClassTwo() };
return ((InterfaceBoth) Mixin.create(interfaces, delegates));
}
<!-- Create mixin instance -->
<bean id="mixin" class="org.literadix.tests.mixins.InterfaceBoth" factory-method="createInstance">
<property name="password" ref="password"/>
</bean>
/**
* Load mixin by spring bean.
*/
@Test
public final void testSpring() {
final ApplicationContext sCtx = new ClassPathXmlApplicationContext("Application.xml");
final InterfaceBoth instance = sCtx.getBean(InterfaceBoth.class);
Assert.assertNotNull(instance.helloOne());
Assert.assertNotNull(instance.helloTwo());
Assert.assertNotNull(instance.getPassword());
log.debug("service instance: {}", instance.getService());
Assert.assertNotNull(instance.getService());
}
I have also injected by a property a value (password) into that instance. What is not working is injecting a resource by annotation. My complete spring definition is as this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName">
<!-- Enable annotations. -->
<bean id="annotations" class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
<bean id="password" class="java.lang.String">
<constructor-arg value="password"/>
</bean>
<!-- Service bean -->
<bean id="service" class="org.literadix.tests.mixins.NewServiceImpl">
</bean>
<!-- Create mixin instance -->
<bean id="mixin" class="org.literadix.tests.mixins.InterfaceBoth" factory-method="createInstance">
<property name="password" ref="password"/>
</bean>
</beans>
public class ClassOne implements InterfaceOne {
/**
* !!! THIS SHOULD BE SET BY SPRING !!!
*/
@Resource
public NewService service;
...
Could some spring expert review my example and tell me why it is not working for the annotation resolving of ressources? I suppose that this is a problem of the spring bean loading life cycle. But I can not find a solution for this.
I packed everything into one github repo. Please just download it if you want to test it on your machine:
https://github.com/literadix/JavaMixins https://github.com/literadix/JavaMixins.git
Thank you very much,
Maciej
Upvotes: 1
Views: 307
Reputation: 1407
I have now got an idea how to solve this problem. Jeremie B has written that the object creattion is outside of spring and this is abolutely the fact. So a solution is to write a factory bean, which is created by spring framework and which will get set the interfaces initially. This factory can be then used to create the mixin and it will set the required dependencies. But thousands word are are harder to understand than just looking on the following source code:
<bean id="mixinFactory" class="org.literadix.tests.mixins.InterfaceBoth.Factory"/>
<!-- Create mixin instance -->
<bean id="mixin" scope="prototype" class="org.literadix.tests.mixins.InterfaceBoth" factory-bean="mixinFactory" factory-method="create">
<property name="password" ref="password"/>
</bean>
public interface InterfaceBoth extends InterfaceOne, InterfaceTwo {
/** Logger. */
final static Logger log = LoggerFactory.getLogger(InterfaceBoth.class);
/**
* Factory to create a mixin instance from both interfaces and both implementations.
*
* @return Merged instance
*/
static InterfaceBoth createInstance() {
return new Factory().create();
}
static class Factory {
@Autowired(required = false)
NewService service;
InterfaceBoth create(){
log.debug("created instance {}", service);
final Class<?>[] interfaces = new Class[] { InterfaceOne.class, InterfaceTwo.class, InterfaceBoth.class };
final Object[] delegates = new Object[] { new ClassOne() {{setService(service);}}, new ClassTwo() };
return ((InterfaceBoth) Mixin.create(interfaces, delegates));
}
}
}
Just look into my repository for a fresh and corrected version:
https://github.com/literadix/JavaMixins
Finally words: this solution is not only working for spring but as the micin factory is a CGLib factory, it can be used in plain java applications only.
Upvotes: 1