Spring context portable extension
trossmy Feb 18, 2010 1:50 PMI have created a portable extension that injects all the beans of the spring context into the cdi context like this:
package weld.example.portable.extension.spring;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessProducer;
import javax.enterprise.inject.spi.Producer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: rossmyt
* Date: 18.02.2010
* Time: 09:22:28
*/
public class SpringContextExtension implements Extension
{
private ApplicationContext applicationContext;
private List<Bean> beans= new java.util.ArrayList<Bean>();
void processAnnotatedType(@Observes ProcessAnnotatedType pat)
{
boolean isSpring = pat.getAnnotatedType().isAnnotationPresent(SpringContext.class);
if (isSpring)
{
SpringContext springContext = pat.getAnnotatedType().getAnnotation(SpringContext.class);
String configFile = springContext.configFile();
applicationContext = new ClassPathXmlApplicationContext(configFile);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (final String beanDefinitionName : beanDefinitionNames)
{
final Object bean = applicationContext.getBean(beanDefinitionName);
final Class type = applicationContext.getType(beanDefinitionName);
Scope scope = bean.getClass().getAnnotation(Scope.class);
Class cdiScope= ApplicationScoped.class;
if (scope!=null)
{
String scopeName = scope.value();
if (scopeName.equals("request"))
{
cdiScope= RequestScoped.class;
}
else if (scopeName.equals("session"))
{
cdiScope= SessionScoped.class;
}
}
final Class scp=cdiScope;
final Set<Type> types = new HashSet<Type>()
{
{
add(type);
add(Object.class);
} };
Bean<?> cdiBean = new Bean<Object>()
{
@Override
public Set<Type> getTypes()
{
return types;
}
@Override
public Set<Annotation> getQualifiers()
{
return Collections.emptySet();
}
@SuppressWarnings({"unchecked"})
@Override
public Class<? extends Annotation> getScope()
{
return scp;
}
@Override
public String getName()
{
return beanDefinitionName;
}
@Override
public Set<Class<? extends Annotation>> getStereotypes()
{
return Collections.emptySet();
}
@Override
public Class<?> getBeanClass()
{
return type;
}
@Override
public boolean isAlternative()
{
return false;
}
@Override
public boolean isNullable()
{
return false;
}
@Override
public Set<InjectionPoint> getInjectionPoints()
{
return Collections.emptySet();
}
@Override
public Object create(CreationalContext<Object> objectCreationalContext)
{
return bean;
}
@Override
public void destroy(Object instance, CreationalContext<Object> objectCreationalContext)
{
objectCreationalContext.release();
}
};
beans.add(cdiBean);
}
}
}
void afterBeanDiscovery(@Observes AfterBeanDiscovery abd)
{
for (Bean bean:beans)
{
abd.addBean(bean);
}
System.out.println("Added spring context!");
}
}
with the SpringContext @interface
package weld.example.portable.extension.spring;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* User: rossmyt
* Date: 18.02.2010
* Time: 09:27:36
*/
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface SpringContext
{
public String configFile () default "application.xml";
}
The Spring context is injected in this bean
package weld.example;
import java.io.Serializable;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import weld.example.portable.extension.spring.SpringContext;
/**
* User: rossmyt
* Date: 17.02.2010
* Time: 16:41:35
*/
@Named(value = "init")
@ApplicationScoped
@SpringContext
public class Init implements Serializable
{
@Produces
@ApplicationScoped
@PersistenceContext(unitName = "foo")
EntityManager em;
}
I test it with the following spring config file application.xml
<?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"> <bean id="springTest" class="weld.example.SpringTest"> <property name="doesItWork" value="yes"/> </bean> </beans>
and
package weld.example;
import java.io.Serializable;
/**
* User: rossmyt
* Date: 18.02.2010
* Time: 11:53:57
*/
public class SpringTest implements Serializable
{
private String doesItWork;
public String getDoesItWork()
{
return doesItWork;
}
public void setDoesItWork(String doesItWork)
{
this.doesItWork = doesItWork;
}
}
So far so good. If I test with a jsf page
<h1>#{springTest.doesItWork}</h1>everything works as expected.
But if I inject the springTest bean into another bean like this
@Inject SpringTest springTest;
a new Instance of SpringTest is created, with springTest.getDoesItWork returning null.
On the other hand, if I inject the beanManager like this
@Inject BeanManager beanManager;
then beanManager.getBeans(springTest
) returns a Set containing the expected springTest bean with springTest.getDoesItWork() returning 'yes'
So, what is it that I don't understand correctly?