Fix the issue Felix-739.
Visible annotations on methods are now moved to iPOJO methods replacing those methods.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@701987 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
index 4a3f354..71b3837 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -23,6 +23,7 @@
 import java.util.List;

 import java.util.Map;

 

+import org.objectweb.asm.AnnotationVisitor;

 import org.objectweb.asm.ClassVisitor;

 import org.objectweb.asm.FieldVisitor;

 import org.objectweb.asm.MethodVisitor;

@@ -71,6 +72,12 @@
      * List of visited inner class owned by the implementation class.

      */

     private List m_inners = new ArrayList();

+    

+    /**

+     * <code>true</code> if the class supports annotations.

+     * This enables the analysis of the code to find and moves annotations.

+     */

+    private boolean m_supportAnnotation = false;

 

     /**

      * Check if the _cm field already exists.

@@ -150,6 +157,8 @@
      */

     public void visit(int version, int access, String name, String signature,

             String superName, String[] interfaces) {

+

+        m_supportAnnotation = version > V1_4 && version < V1_1;

         

         if (! superName.equals("java/lang/Object")) {

             m_superClass = superName.replace('/', '.');

@@ -180,18 +189,27 @@
         if (!name.equals("<clinit>")) { 

             

             if (name.equals("<init>")) {

-                m_methods.add(new MethodDescriptor("$init", desc));

+                final MethodDescriptor md = new MethodDescriptor("$init", desc);

+                m_methods.add(md);

+                if (m_supportAnnotation) {

+                    return new AnnotationCollector(md); 

+                }

             } else {

                 // Avoid constructors.

                 if (!(name.startsWith("_get") || // Avoid getter method

                         name.startsWith("_set") || // Avoid setter method

                         name.equals("_setComponentManager") || // Avoid the set method

                         name.equals("getComponentInstance"))) { // Avoid the getComponentInstance method

-                    m_methods.add(new MethodDescriptor(name, desc));

+                    final MethodDescriptor md = new MethodDescriptor(name, desc);

+                    m_methods.add(md);

+                    if (m_supportAnnotation) {

+                        return new AnnotationCollector(md); 

+                    }

                 }

             }

             

-        }

+        }        

+        

         return null;

     }

     

@@ -226,5 +244,413 @@
     public List getInnerClasses() {

         return m_inners;

     }

+    

+    /**

+     * This class collects annotations in a method.

+     * This class creates an {@link AnnotationDescriptor} 

+     * if an annotation is found during the visit.

+     *  @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+     */

+    private final class AnnotationCollector extends EmptyVisitor {

+        /**

+         * The method descriptor of the visited method.

+         */

+        private MethodDescriptor m_method;

+        

+        /**

+         * Creates an annotation collector.

+         * @param md the method descriptor of the visited method.

+         */

+        private AnnotationCollector(MethodDescriptor md) {

+            m_method = md;

+        }

+        

+        /**

+         * Visits an annotation.

+         * This class checks the visibility. If the annotation is visible,

+         * creates the {@link AnnotationDescriptor} corresponding to this annotation

+         * to visit this annotation. This {@link AnnotationDescriptor} is added to

+         * the {@link MethodDescriptor} of the visited method.

+         * @param name the name of the annotation

+         * @param visible is the annotation visible at runtime

+         * @return the {@link AnnotationDescriptor} to visit this annotation or

+         * <code>null</code> if the annotation is not visible.

+         * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)

+         */

+        public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+            if (visible) {

+                AnnotationDescriptor ann = new AnnotationDescriptor(name, visible);

+                m_method.addAnnotation(ann);

+                return ann;

+            }

+            return null;

+        }

+    }

+    

+    /**

+     * Describes a method or constructor annotation.

+     * This allows creating a copy of the annotations found in the original class

+     * to move them on inserted method. This class implements an

+     * {@link AnnotationVisitor} in order to create the copy.

+     * This class contains a <code>visit</code> method re-injecting the

+     * annotation in the generated method.

+     * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+     */

+    public class AnnotationDescriptor implements AnnotationVisitor {

+        /**

+         * The name of the annotation.

+         */

+        private String m_name;

+        /**

+         * Is the annotation visible at runtime?

+         */

+        private boolean m_visible;

+        /**

+         * The description of the annotation.

+         * This attribute is set only for nested annotations.

+         */

+        private String m_desc;

+        /**

+         * The list of 'simple' attributes.

+         */

+        private List m_simples = new ArrayList(0);

+        /**

+         * The list of attribute containing an

+         * enumeration value.

+         */

+        private List m_enums = new ArrayList(0);

+        /**

+         * The list of attribute which are

+         * annotations.

+         */

+        private List m_nested = new ArrayList(0);

+        /**

+         * The list of attribute which are

+         * arrays. 

+         */

+        private List m_arrays = new ArrayList(0);

+        

+        

+        /**

+         * Creates an annotation descriptor.

+         * This constructor is used for 'root' annotations.

+         * @param name the name of the  annotation

+         * @param visible the visibility of the annotation at runtime

+         */

+        public AnnotationDescriptor(String name, boolean visible) {

+            m_name = name;

+            m_visible = visible;

+        }

+        

+        /**

+         * Creates an annotation descriptor.

+         * This constructor is used for nested annotations.

+         * @param name the name of the  annotation

+         * @param desc the descriptor of the annotation

+         */

+        public AnnotationDescriptor(String name, String desc) {

+            m_name = name;

+            m_visible = true;

+            m_desc = desc;

+        }

+

+

+        /**

+         * Visits a simple attribute.

+         * @param arg0 the attribute name

+         * @param arg1 the attribute value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            m_simples.add(new SimpleAttribute(arg0, arg1));

+        }

+

+

+        /**

+         * Visits a nested annotation.

+         * @param arg0 the attribute name

+         * @param arg1 the annotation descriptor

+         * @return the annotation visitor parsing the nested annotation

+         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)

+         */

+        public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+            AnnotationDescriptor ad = new AnnotationDescriptor(arg0, arg1);

+            m_nested.add(ad);

+            return ad;

+        }

+

+

+        /**

+         * Visits an array attribute.

+         * @param arg0 the name of the attribute

+         * @return the annotation visitor parsing the content of the array,

+         * uses a specific {@link ArrayAttribute} to parse this array

+         * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)

+         */

+        public AnnotationVisitor visitArray(String arg0) {

+            ArrayAttribute aa = new ArrayAttribute(arg0);

+            m_arrays.add(aa);

+            return aa;

+        }

+

+

+        /**

+         * End of the visit.

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() { }

+

+

+        /**

+         * Visits an enumeration attribute.

+         * @param arg0 the attribute name

+         * @param arg1 the enumeration descriptor

+         * @param arg2 the attribute value

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)

+         */

+        public void visitEnum(String arg0, String arg1, String arg2) {

+            m_enums.add(new EnumAttribute(arg0, arg1, arg2));

+        }

+        

+        /**

+         * Methods allowing to recreate the visited (stored) annotation

+         * into the destination method.

+         * This method recreate the annotations itself and any other 

+         * attributes.

+         * @param mv the method visitor visiting the destination method.

+         */

+        public void visit(MethodVisitor mv) {

+            AnnotationVisitor av = mv.visitAnnotation(m_name, m_visible);

+            for (int i = 0; i < m_simples.size(); i++) {

+                ((SimpleAttribute) m_simples.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_enums.size(); i++) {

+                ((EnumAttribute) m_enums.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_nested.size(); i++) {

+                ((AnnotationDescriptor) m_nested.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_arrays.size(); i++) {

+                ((ArrayAttribute) m_arrays.get(i)).visit(av);

+            }

+            av.visitEnd();

+        }

+        

+        /**

+         * Method allowing to recreate the visited (stored) annotation

+         * into the destination annotation. This method is used only

+         * for nested annotation.

+         * @param mv the annotation visitor to populate with the stored

+         * annotation

+         */

+        public void visit(AnnotationVisitor mv) {

+            AnnotationVisitor av = mv.visitAnnotation(m_name, m_desc);

+            for (int i = 0; i < m_simples.size(); i++) {

+                ((SimpleAttribute) m_simples.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_enums.size(); i++) {

+                ((EnumAttribute) m_enums.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_nested.size(); i++) {

+                ((AnnotationDescriptor) m_nested.get(i)).visit(av);

+            }

+            for (int i = 0; i < m_arrays.size(); i++) {

+                ((ArrayAttribute) m_arrays.get(i)).visit(av);

+            }

+            av.visitEnd();

+        }

+        

+        

+    }

+    

+    /**

+     * Describes an array attribute.

+     * This class is able to visit an annotation array attribute, and to

+     * recreate this array on another annotation.

+     * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+     */

+    public class ArrayAttribute implements AnnotationVisitor {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The content of the parsed array.

+         */

+        private List m_content = new ArrayList();

+        

+        /**

+         * Creates an array attribute.

+         * @param name the name of the attribute.

+         */

+        public ArrayAttribute(String name) {

+            m_name = name;

+        }

+

+        /**

+         * Visits the content of the array. This method is called for 

+         * simple values. 

+         * @param arg0 <code>null</code>

+         * @param arg1 the value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            m_content.add(arg1);

+        }

+

+        /**

+         * Visits the content of the array. This method is called for 

+         * nested annotations (annotations contained in the array). 

+         * @param arg0 <code>null</code>

+         * @param arg1 the annotation descriptor

+         * @return an {@link AnnotationDescriptor} which creates a copy of

+         * the contained annotation.

+         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)

+         */

+        public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+            AnnotationDescriptor ad = new AnnotationDescriptor(null, arg1);

+            m_content.add(ad);

+            return ad;

+        }

+

+        /**

+         * Visits the content of the array. This method is called for 

+         * nested arrays (arrays contained in the array). 

+         * @param arg0 <code>null</code>

+         * @return an {@link ArrayDescriptor} which creates a copy of

+         * the contained array.

+         * @see org.objectweb.asm.AnnotationVisitor#visitArray(String)

+         */

+        public AnnotationVisitor visitArray(String arg0) {

+            ArrayAttribute aa = new ArrayAttribute(null);

+            m_content.add(aa);

+            return aa;

+        }

+

+        /**

+         * End of the array attribute visit.

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() {  }

+

+        /**

+         * Visits the content of the array. This method is called for 

+         * enumeration values. 

+         * @param arg0 <code>null</code>

+         * @param arg1 the enumeration descriptor

+         * @param arg2 the value

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)

+         */

+        public void visitEnum(String arg0, String arg1, String arg2) {

+            EnumAttribute ea = new EnumAttribute(null, arg1, arg2);

+            m_content.add(ea);

+        }

+        

+        /**

+         * Recreates the visited array attribute. This method

+         * handle the generation of the object embedded in the

+         * array.

+         * @param av the annotation visitor on which the array attribute

+         * needs to be injected.

+         */

+        public void visit(AnnotationVisitor av) {

+            AnnotationVisitor content = av.visitArray(m_name);

+            for (int i = 0; i < m_content.size(); i++) {

+                Object component = m_content.get(i);

+                if (component instanceof AnnotationDescriptor) {

+                    ((AnnotationDescriptor) component).visit(content);

+                } else if (component instanceof EnumAttribute) {

+                    ((EnumAttribute) component).visit(content);

+                } else if (component instanceof ArrayAttribute) {

+                    ((ArrayAttribute) component).visit(content);

+                } else { // Simple

+                    content.visit(null, component);

+                }

+            }

+            content.visitEnd();

+        }

+                

+    }

+    

+    /**

+     * Describes a simple attribute.

+     * This class is able to visit an annotation simple attribute, and to

+     * recreate this attribute on another annotation.

+     * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+     */

+    public final class SimpleAttribute {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The value of the attribute.

+         */

+        private Object m_value;

+        

+        /**

+         * Creates a simple attribute.

+         * @param name the name of the attribute

+         * @param object the value of the attribute

+         */

+        private SimpleAttribute(String name, Object object) {

+            m_name = name;

+            m_value = object;

+        }

+        

+        /**

+         * Recreates the attribute on the given annotation.

+         * @param visitor the visitor on which the attribute needs

+         * to be injected.

+         */

+        public void visit(AnnotationVisitor visitor) {

+            visitor.visit(m_name, m_value);

+        }

+    }

+    

+    /**

+     * Describes an attribute. The value of this attribute is an enumerated

+     * value.

+     * This class is able to visit an annotation enumeration attribute, and to

+     * recreate this attribute on another annotation.

+     * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+     */

+    public final class EnumAttribute {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The descriptor of the enumeration.

+         */

+        private String m_desc;

+        /**

+         * The value of the attribute.

+         */

+        private String m_value;

+        

+        /**

+         * Creates a enumeration attribute.

+         * @param name the name of the attribute.

+         * @param desc the descriptor of the {@link Enum}

+         * @param value the enumerated value

+         */

+        private EnumAttribute(String name, String desc, String value) {

+            m_name = name;

+            m_value = value;

+            m_desc = desc;

+        }

+        

+        /**

+         * Recreates the attribute on the given annotation.

+         * @param visitor the visitor on which the attribute needs

+         * to be injected.

+         */

+        public void visit(AnnotationVisitor visitor) {

+            visitor.visitEnum(m_name, m_desc, m_value);

+        }

+        

+    }

+

 

 }

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
index 1841ad5..844ab9a 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -20,6 +20,7 @@
 

 import java.util.Set;

 

+import org.objectweb.asm.AnnotationVisitor;

 import org.objectweb.asm.Label;

 import org.objectweb.asm.MethodVisitor;

 import org.objectweb.asm.Opcodes;

@@ -65,6 +66,26 @@
         m_superDetected = false;

         m_fields = fields;

     }

+    

+    /**

+     * Visits an annotation.

+     * If the annotation is visible, the annotation is removed. In fact

+     * the annotation was already moved to the method replacing this one.

+     * If the annotation is not visible, this annotation is kept on this method.

+     * @param name the name of the annotation

+     * @param visible the annotation visibility

+     * @return the <code>null</code> if the annotation is visible, otherwise returns

+     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}

+     * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+        // Annotations are moved to the injected constructor.

+        if (visible) {

+            return null;

+        } else {

+            return super.visitAnnotation(name, visible);

+        }

+    }

 

 

     /** 

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
index f2cebf7..c572169 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -96,7 +96,7 @@
             ClassReader cr0 = new ClassReader(is2);

             ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);

             //CheckClassAdapter ch = new CheckClassAdapter(cw0);

-            MethodCreator preprocess = new MethodCreator(cw0, m_fields);

+            MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);

             cr0.accept(preprocess, ClassReader.SKIP_FRAMES);

             is2.close();

             finalWriter = cw0;

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
index c698a6b..06e72ed 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
@@ -20,6 +20,7 @@
 

 import java.util.Set;

 

+import org.objectweb.asm.AnnotationVisitor;

 import org.objectweb.asm.MethodVisitor;

 import org.objectweb.asm.Opcodes;

 import org.objectweb.asm.commons.GeneratorAdapter;

@@ -78,5 +79,25 @@
         }

         super.visitFieldInsn(opcode, owner, name, desc);

     }

+    

+    /**

+     * Visits an annotation.

+     * If the annotation is visible, the annotation is removed. In fact

+     * the annotation was already moved to the method replacing this one.

+     * If the annotation is not visible, this annotation is kept on this method.

+     * @param name the name of the annotation

+     * @param visible the annotation visibility

+     * @return the <code>null</code> if the annotation is visible, otherwise returns

+     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}

+     * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+        // Annotations are moved to the injected constructor.

+        if (visible) {

+            return null;

+        } else {

+            return super.visitAnnotation(name, visible);

+        }

+    }

 

 }

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
index c81e3f8..8495f4a 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
@@ -24,6 +24,7 @@
 import java.util.Map;

 import java.util.Set;

 

+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;

 import org.objectweb.asm.ClassAdapter;

 import org.objectweb.asm.ClassVisitor;

 import org.objectweb.asm.FieldVisitor;

@@ -112,19 +113,28 @@
      * This set contains field name generate from method id.

      */

     private List m_methodFlags = new ArrayList(); 

+    

+    /**

+     * The list of methods visited during the previous analysis.

+     * This list allows getting annotations to move to generated

+     * method.

+     */

+    private List m_visitedMethods = new ArrayList();

 

     /**

      * Constructor.

      * @param arg0 : class visitor.

      * @param fields : fields map detected during the previous class analysis.

+     * @param methods : the list of the detected method during the previous class analysis.

      */

-    public MethodCreator(ClassVisitor arg0, Map fields) {

+    public MethodCreator(ClassVisitor arg0, Map fields, List methods) {

         super(arg0);

         m_fields = fields.keySet();

+        m_visitedMethods = methods;

     }

 

     /**

-     * Vist method.

+     * Visit method.

      * This method store the current class name.

      * Moreover the POJO interface is added to the list of implemented interface.

      * Then the Instance manager field is added.

@@ -161,16 +171,16 @@
         if (name.equals("<clinit>") || name.equals("class$")) { return super.visitMethod(access, name, desc, signature, exceptions); }

         // The constructor is manipulated separately

         if (name.equals("<init>")) {

-            

+            MethodDescriptor md = getMethodDescriptor("$init", desc);

             // 1) change the constructor descriptor (add a component manager arg as first argument)

             String newDesc = desc.substring(1);

             newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

 

             Type[] args = Type.getArgumentTypes(desc);

             if (args.length == 0) {

-                generateEmptyConstructor(access, signature, exceptions);

+                generateEmptyConstructor(access, signature, exceptions, md.getAnnotations());

             } else if (args.length == 1 && args[0].getClassName().equals("org.osgi.framework.BundleContext")) {

-                generateBCConstructor(access, signature, exceptions);

+                generateBCConstructor(access, signature, exceptions, md.getAnnotations());

             } else {

                 // Do nothing, the constructor does not match.

                 return cv.visitMethod(access, name, desc, signature, exceptions);

@@ -188,9 +198,8 @@
 

         if ((access & ACC_STATIC) == ACC_STATIC) { return super.visitMethod(access, name, desc, signature, exceptions); }

 

-        

-        generateMethodHeader(access, name, desc, signature, exceptions);

-        

+        MethodDescriptor md = getMethodDescriptor(name, desc);

+        generateMethodHeader(access, name, desc, signature, exceptions, md.getAnnotations());

         

         String id = generateMethodFlag(name, desc);

         if (! m_methodFlags.contains(id)) {

@@ -204,6 +213,24 @@
     }

     

     /**

+     * Gets the method descriptor for the specified name and descriptor.

+     * The method descriptor is looked inside the 

+     * {@link MethodCreator#m_visitedMethods}

+     * @param name the name of the method

+     * @param desc the descriptor of the method

+     * @return the method descriptor or <code>null</code> if not found.

+     */

+    private MethodDescriptor getMethodDescriptor(String name, String desc) {

+        for (int i = 0; i < m_visitedMethods.size(); i++) {

+            MethodDescriptor md = (MethodDescriptor) m_visitedMethods.get(i);

+            if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {

+                return md;

+            }

+        }

+        return null;

+    }

+    

+    /**

      * Visit a Field.

      * This field access is replaced by an invocation to the getter method or to the setter method.

      * (except for static field).

@@ -252,14 +279,26 @@
      * @param access : access flag

      * @param signature : method signature

      * @param exceptions : declared exception

+     * @param annotations : the annotations to move to this constructor.

      */

-    private void generateEmptyConstructor(int access, String signature, String[] exceptions) {

+    private void generateEmptyConstructor(int access, String signature, String[] exceptions, List annotations) {

         MethodVisitor mv = cv.visitMethod(access, "<init>", "()V", signature, exceptions);

         mv.visitCode();

         mv.visitVarInsn(ALOAD, 0);

         mv.visitInsn(ACONST_NULL);

         mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", "(Lorg/apache/felix/ipojo/InstanceManager;)V");

         mv.visitInsn(RETURN);

+   

+        // Move annotations

+        if (annotations != null) {

+            for (int i = 0; i < annotations.size(); i++) {

+                AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);

+                ad.visit(mv);

+                System.out.println("Inject annotation : " + ad);

+            }

+        }

+        

+        

         mv.visitMaxs(0, 0);

         mv.visitEnd();

     }

@@ -271,8 +310,9 @@
      * @param access : access flag

      * @param signature : method signature

      * @param exceptions : declared exception

+     * @param annotations : the annotations to move to this constructor.

      */

-    private void generateBCConstructor(int access, String signature, String[] exceptions) {

+    private void generateBCConstructor(int access, String signature, String[] exceptions, List annotations) {

         MethodVisitor mv = cv.visitMethod(access, "<init>", "(Lorg/osgi/framework/BundleContext;)V", signature, exceptions);

         mv.visitCode();

         Label l0 = new Label();

@@ -282,6 +322,15 @@
         mv.visitVarInsn(ALOAD, 1);

         mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", "(Lorg/apache/felix/ipojo/InstanceManager;Lorg/osgi/framework/BundleContext;)V");

         mv.visitInsn(RETURN);

+        

+        // Move annotations

+        if (annotations != null) {

+            for (int i = 0; i < annotations.size(); i++) {

+                AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);

+                ad.visit(mv);

+            }

+        }

+        

         mv.visitMaxs(0, 0);

         mv.visitEnd();

     }

@@ -295,8 +344,9 @@
      * @param desc : method descriptor.

      * @param signature : method signature.

      * @param exceptions : declared exceptions.

+     * @param annotations : the annotations to move to this method.

      */

-    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions) {

+    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions, List annotations) {

         GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc); 

         

         mv.visitCode();

@@ -385,6 +435,15 @@
             mv.visitVarInsn(returnType.getOpcode(ILOAD), result);

         }

         mv.visitInsn(returnType.getOpcode(IRETURN));

+        

+        // Move annotations

+        if (annotations != null) {

+            for (int i = 0; i < annotations.size(); i++) {

+                AnnotationDescriptor ad = (AnnotationDescriptor) annotations.get(i);

+                ad.visit(mv);

+                System.out.println("Inject annotation : " + ad);

+            }

+        }

 

         mv.visitMaxs(0, 0);

         mv.visitEnd();

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
index bd6056c..6e975f9 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -18,6 +18,10 @@
  */

 package org.apache.felix.ipojo.manipulation;

 

+import java.util.ArrayList;

+import java.util.List;

+

+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;

 import org.apache.felix.ipojo.metadata.Attribute;

 import org.apache.felix.ipojo.metadata.Element;

 import org.objectweb.asm.Type;

@@ -42,6 +46,18 @@
      * Argument types.

      */

     private String[] m_arguments;

+    

+    /**

+     * The descriptor of the method.

+     */

+    private String m_desc;

+    

+    

+    /**

+     * The list of {@link AnnotationDescriptor} attached to this

+     * method. 

+     */

+    private List m_annotations;

 

     /**

      * Constructor.

@@ -50,6 +66,7 @@
      */

     public MethodDescriptor(String name, String desc) {

         m_name = name;

+        m_desc = desc;

         Type ret = Type.getReturnType(desc);

         Type[] args = Type.getArgumentTypes(desc);

 

@@ -59,6 +76,25 @@
             m_arguments[i] = getType(args[i]);

         }

     }

+    

+    /**

+     * Add an annotation to the current method.

+     * @param ann annotation to add

+     */

+    public void addAnnotation(AnnotationDescriptor ann) {

+        if (m_annotations == null) {

+            m_annotations = new ArrayList();

+        }

+        m_annotations.add(ann);

+    }

+    

+    public List getAnnotations() {

+        return m_annotations;

+    }

+    

+    public String getDescriptor() {

+        return m_desc;

+    }

 

     /**

      * Compute method manipulation metadata.

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
index d4534c4..aafd81f 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
@@ -31,6 +31,8 @@
  */

 public class CustomAnnotationVisitor extends EmptyVisitor implements AnnotationVisitor {

 

+    //TODO manage enum annotations.

+    

     /**

      * PArent element.

      */

@@ -96,7 +98,7 @@
     }

 

     /**

-     * Visit an 'simple' annotation attribute.

+     * Visit a 'simple' annotation attribute.

      * This method is used for primitive arrays too. 

      * @param arg0 : attribute name

      * @param arg1 : attribute value

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
index 15c2b93..0cc1181 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -52,8 +52,6 @@
 import org.xml.sax.SAXParseException;

 import org.xml.sax.XMLReader;

 

-import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;

-

 /**

  * Pojoization allows creating an iPOJO bundle from a "normal" bundle.  

  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
index c583f8c..855b7b2 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -246,6 +246,14 @@
     }

 

 

+    /**

+     * An error occurs during the XML-Schema checking.

+     * This method propagates the error except if the error concerns

+     * no XML-Schemas are used   (<code>cvc-elt.1</code>).

+     * @param saxparseexception the checking error

+     * @throws SAXException the propagated exception

+     * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)

+     */

     public void error(SAXParseException saxparseexception) throws SAXException {

         if (saxparseexception.getMessage().contains("cvc-elt.1")) {

             return; // Do not throw an exception when no schema defined.

@@ -254,13 +262,27 @@
     }

 

 

+    /**

+     * A fatal error occurs during the XML-Schema checking.

+     * This method always propagates the error.

+     * @param saxparseexception the checking error

+     * @throws SAXException the propagated exception

+     * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)

+     */

     public void fatalError(SAXParseException saxparseexception)

             throws SAXException {

         System.err.println("Fatal error during XML-Schema parsing : " + saxparseexception);

         throw saxparseexception;

     }

 

-

+    /**

+     * A warning was detected during the XML-Schema checking.

+     * This method always propagate the warning message to

+     * {@link System#out}.

+     * @param saxparseexception the checking error

+     * @throws SAXException nothing.

+     * @see org.xml.sax.ErrorHandler#warning(SAXParseException)

+     */

     public void warning(SAXParseException saxparseexception)

             throws SAXException {

         System.err.println("Warning : an error was detected in the metadata file : " + saxparseexception);