[jboss-dev-forums] [Design the new POJO MicroContainer] - Annotation handling impl

alesj do-not-reply at jboss.com
Fri Jul 27 08:48:17 EDT 2007


I've implemented initial version of handling MC beans annotations.
So, before I go into madly testing all the features, backcompatibility, javadocs, ..., it would probably be good to get some feedback on my impl - bad, really bad, so so, good, nice, wonderful, ... :-)

Let me first explain what I did.
In the DescribeAction, after the metadata has been set, I create BeanAnnotationAdapter - currently only BasicBeanAnnotationAdapter.

  | public interface BeanAnnotationAdapter
  | {
  |    /**
  |     * Apply the annotations.
  |     *
  |     * @param context the context
  |     * @throws Throwable for any error
  |     */
  |    void applyAnnotations(KernelControllerContext context) throws Throwable;
  | }
  | 
The main goal is to fill in BeanMetaData with information from @Annotations.

There are 5 different AnnotetedInfo types that need checking:
 - class
 - constructor
 - property
 - method
 - field

I currently don't do field (since there is no matching 'Bean'MetaData), and I differentiate between property and method for the ease of providing matching PropertyMetaData.

The whole idea is to check type's matching MetaDataRetrieval (MDR).
For class this is context's top level MDR, for others it is the component of this top level MDR.
And for constructor|method parameters it is component's component MDR - see the AnnotatedElementMetaDataLoader post issue.

For each annotation there is matching AnnotationPlugin:

  | public interface AnnotationPlugin<T extends AnnotatedInfo, C extends Annotation>
  | {
  |    Class<C> getAnnotation();
  | 
  |    Set<ElementType> getSupportedTypes();
  | 
  |    void applyAnnotation(T info, MetaDataRetrieval retrieval, KernelControllerContext context) throws Throwable;
  | }
  | 

Depending on the ElementType's of @Target on the annotation, matching collections of plugins are filled: classPlugins, constructorPlugins, ...

I then iterate through all possible AnnotatedInfos - ClassInfo, ConstructorInfos, PropertyInfos, MethodInfos, static MethodInfos, FieldInfos - and apply matching plugins. For each AnnotatedInfo I iterate over with all possible plugins.

  |       // methods
  |       Set<MethodInfo> methods = info.getMethods();
  |       if (methods != null && methods.isEmpty() == false)
  |       {
  |          for(MethodInfo mi : methods)
  |          {
  |             Signature mis = new MethodSignature(mi.getName(), Configurator.getParameterTypes(trace, mi.getParameterTypes()));
  |             MetaDataRetrieval cmdr = retrieval.getComponentMetaDataRetrieval(mis);
  |             if (cmdr != null)
  |             {
  |                for(AnnotationPlugin plugin : methodAnnotationPlugins)
  |                   plugin.applyAnnotation(mi, cmdr, context);
  |             }
  |          }
  |       }
  | 

If the AnnotationItem is found in MDR and metadata is not yet set, I apply information from the annotation.

  |    public final void applyAnnotation(T info, MetaDataRetrieval retrieval, KernelControllerContext context) throws Throwable
  |    {
  |       AnnotationItem<C> item = retrieval.retrieveAnnotation(getAnnotation());
  |       if (item == null || isMetaDataAlreadyPresent(info, item.getAnnotation(), context))
  |          return;
  |       internalApplyAnnotation(info, retrieval, item.getAnnotation(), context);
  |    }
  | 

I'm also supporting constructor|method parameter annotation injection.
In order for this to work, all parameters must have of the Annotation2ValueMetaDataAdapter annotations present: @Inject, @StringValue, @ValueFactory, @ThisValue, @NullValue.

So much for simple explanation. :-)

This is what you can currently do:

  | @Aliases({"al", "test"})
  | @Demands({"otherBean"})
  | @Depends({"serviceBean"})
  | @Supplys({"txBean"})
  | public class SimpleInject
  | {
  |    private int intVF;
  |    private TestBean testBean;
  |    private Set<MyDeployer> deployers;
  | 
  |    public int getVf()
  |    {
  |       return intVF;
  |    }
  | 
  |    @FactoryMethod
  |    public static SimpleInject getInstance(@NullValue Object someNull)
  |    {
  |       return new SimpleInject();
  |    }
  | 
  |    @Start
  |    public void startMeUp(@Inject(bean = "lifecycleBean") TestBean bean, @ValueFactory(bean="valueBean", method = "getValue", parameter = "123") int value)
  |    {
  |       intVF =- value;      
  |    }
  | 
  |    @StringValue("123")
  |    public void setVf(int vf)
  |    {
  |       this.intVF = vf;
  |    }
  | 
  |    @Install
  |    public void addDeployer(MyDeployer deployer)
  |    {
  |       if (deployers == null)
  |          deployers = new HashSet<MyDeployer>();
  |       deployers.add(deployer);
  |    }
  | 
  |    @Uninstall
  |    public void removeDeployer(MyDeployer deployer)
  |    {
  |       deployers.remove(deployer);
  |    }
  | 
  |    @InstallMethod
  |    public void whenInstalled(@ThisValue SimpleInject me, @NullValue Object plainNull)
  |    {
  |       System.out.println(me == this);
  |       System.out.println("plainNull = " + plainNull);
  |    }
  | 
  |    @UninstallMethod
  |    public void withUninstall(@ThisValue SimpleInject me, @NullValue Object plainNull)
  |    {
  |       System.out.println(me == this);
  |       System.out.println("plainNull = " + plainNull);
  |    }
  | 
  |    public TestBean getTestBean()
  |    {
  |       return testBean;
  |    }
  | 
  |    @Inject(bean = "testBean")
  |    public void setTestBean(TestBean bean)
  |    {
  |       this.testBean = bean; 
  |    }
  | 
  | public class TestConstructorBean
  | {
  |    @Constructor
  |    public TestConstructorBean(@Inject(bean = "testBean") TestBean test)
  |    {
  |       System.out.println("test = " + test);
  |    }
  | }
  | 

I'll commit the code, just to make it more simple to see what I did.
There is just one entry point to all this mess - in the DescribeAction.

I removed the old @Annotation lifecycle support - now part of this new approach. 

The BeanMetaData is not cloned yet - a big TODO. :-)

I haven't thought of how exactly this will fit with the factory beans. One step at the time ... ;-)

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4068190#4068190

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4068190



More information about the jboss-dev-forums mailing list