1 Reply Latest reply on May 22, 2008 4:55 PM by Ales Justin

    Annotations scanning part 2

    Ales Justin Master

      I'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.

        • 1. Re: Annotations scanning part 2
          Ales Justin Master

           

          "alesj" wrote:

          I've added a deployer that knows how to scan newly added @Bean and @BeanFactory annotations - corresponding to MC beans and beanfactories.

          I've added this code to be able to easily remove added bean components in BeanScanningDeployer:
           public void deploy(DeploymentUnit unit, AnnotationEnvironment env) throws DeploymentException
           {
           Map<String, DeploymentUnit> components = null;
          + Set<String> beanNames = null;
          
           Set<Class<?>> beans = env.classIsAnnotatedWith(Bean.class);
           if (beans != null && beans.isEmpty() == false)
           {
           components = new HashMap<String, DeploymentUnit>();
          + beanNames = new HashSet<String>();
           mapComponents(unit, components);
          
           for (Class<?> beanClass : beans)
          @@ -107,6 +109,7 @@
           .setAutowireCandidate(bean.autowireCandidate());
          
           KernelDeploymentDeployer.addBeanComponent(unit, builder.getBeanMetaData());
          + beanNames.add(name);
           }
           else
           {
          @@ -123,6 +126,7 @@
           {
           components = new HashMap<String, DeploymentUnit>();
           mapComponents(unit, components);
          + beanNames = new HashSet<String>();
           }
          
           for (Class<?> beanFactoryClass : beanFactories)
          @@ -157,7 +161,10 @@
          
           List<BeanMetaData> bfBeans = gbfmd.getBeans();
           for (BeanMetaData bfb : bfBeans)
          + {
           KernelDeploymentDeployer.addBeanComponent(unit, bfb);
          + beanNames.add(name);
          + }
           }
           else
           {
          @@ -165,10 +172,22 @@
           log.info("BeanMetaData with such name already exists: " + bmd + ", scanned: " + beanFactoryClass);
           }
           }
          +
          + if (beanNames != null && beanNames.isEmpty() == false)
          + unit.addAttachment(getClass() + ".Beans", beanNames);
           }
           }
          
          - // TODO - undeploy!!
          + public void undeploy(DeploymentUnit unit, AnnotationEnvironment deployment)
          + {
          + @SuppressWarnings("unchecked")
          + Set<String> beanNames = unit.getAttachment(getClass() + ".Beans", Set.class);
          + if (beanNames != null)
          + {
          + for(String name : beanNames)
          + unit.removeComponent(name);
          + }
          + }
          

          Can we consider this legit? :-)