Annotations scanning part 2
alesj May 19, 2008 10:13 AMI'm slowly adding more and more tests to this (resolved) issue:
- http://www.jboss.com/index.html?module=bb&op=viewtopic&t=134098
I've added a deployer that knows how to scan newly added @Bean and @BeanFactory annotations - corresponding to MC beans and beanfactories.
The code that does this is pretty simple:
public void deploy(DeploymentUnit unit, AnnotationEnvironment env) throws DeploymentException
{
Set<Class<?>> beans = env.classIsAnnotatedWith(Bean.class);
then you can do what ever you like with that information. ;-)
This is what I do in my case (create new BeanMetaData if it doesn't exist yet):
for (Class<?> beanClass : beans)
{
Bean bean = beanClass.getAnnotation(Bean.class);
String name = bean.name();
if (name == null)
throw new IllegalArgumentException("Null bean name: " + beanClass);
DeploymentUnit component = components.get(name);
BeanMetaData bmd = null;
if (component != null)
bmd = component.getAttachment(BeanMetaData.class);
if (bmd == null)
{
BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(name, beanClass.getName());
String[] aliases = bean.aliases();
if (aliases != null && aliases.length > 0)
builder.setAliases(new HashSet<Object>(Arrays.asList(aliases)));
builder.setMode(bean.mode())
.setAccessMode(bean.accessMode())
.setAutowireType(bean.autowireType())
.setErrorHandlingMode(bean.errorHandlingMode())
.setAutowireCandidate(bean.autowireCandidate());
addBeanComponent(unit, builder.getBeanMetaData());
}
For all those who missed recent annotations scanning work, this is the class that should be of interest - AnnotationEnvironment - simply pull it out from the right DeploymentUnit as attachment:
/**
* Information holder about annotation processing.
*
* @author <a href="mailto:ales.justin@jboss.com">Ales Justin</a>
*/
public interface AnnotationEnvironment
{
/**
* Get all classes annotated with annotation param.
*
* @param annotation the annotation we're querying for
* @return set of matching classes
*/
Set<Class<?>> classIsAnnotatedWith(Class<? extends Annotation> annotation);
/**
* Get all classes who have some constructor annotated with annotation param.
*
* @param annotation the annotation we're querying for
* @return set of matching classes
*/
<A extends Annotation> Set<Element<A, Constructor>> classHasConstructorAnnotatedWith(Class<A> annotation);
/**
* Get all classes who have some field annotated with annotation param.
*
* @param annotation the annotation we're querying for
* @return set of matching classes
*/
<A extends Annotation> Set<Element<A, Field>> classHasFieldAnnotatedWith(Class<A> annotation);
/**
* Get all classes who have some method annotated with annotation param.
*
* @param annotation the annotation we're querying for
* @return set of matching classes
*/
<A extends Annotation> Set<Element<A, Method>> classHasMethodAnnotatedWith(Class<A> annotation);
/**
* Get all classes who have some method's/constructor's parameter annotated with annotation param.
*
* @param annotation the annotation we're querying for
* @return set of matching classes
*/
<A extends Annotation> Set<Element<A, AccessibleObject>> classHasParameterAnnotatedWith(Class<A> annotation);
}
The code handles class loading lazily (Javassist + keeping weak ref to classloader from unit), meaning class won't get loaded until you actually need the information, e.g. AOP could modify it before.