Fix FELIX-3749 (https://issues.apache.org/jira/browse/FELIX-3749)

Apply patch from Guillaume Sauthier.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1406969 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
index fa48552..b3f7547 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -1,283 +1,280 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-package org.apache.felix.ipojo.manipulation;

-

-import java.util.Set;

-

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

-import org.apache.felix.ipojo.manipulation.annotations.CustomAnnotationVisitor;

-import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;

-import org.objectweb.asm.AnnotationVisitor;

-import org.objectweb.asm.Label;

-import org.objectweb.asm.MethodVisitor;

-import org.objectweb.asm.Opcodes;

-import org.objectweb.asm.Type;

-import org.objectweb.asm.commons.GeneratorAdapter;

-

-

-/**

- * Constructor Adapter.

- * This class adds an instance manager argument (so switch variable index).

- * Moreover, it adapts field accesses to delegate accesses to the instance

- * manager if needed.

- *

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

- */

-public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {

-

-    /**

-     * The class containing the field.

-     * m_owner : String

-     */

-    private String m_owner;

-

-    /**

-     * Is the super call detected ?

-     */

-    private boolean m_superDetected;

-

-    /**

-     * The super class.

-     */

-    private String m_superClass;

-

-    /**

-     * Set of contained fields.

-     */

-    private Set<String> m_fields;

-

-

-    /**

-     * PropertyCodeAdapter constructor.

-     * A new FiledCodeAdapter should be create for each method visit.

-     *

-     * @param mv     the MethodVisitor

-     * @param owner  the name of the class

-     * @param fields the list of contained fields

-     * @param access the constructor access

-     * @param desc   the constructor descriptor

-     * @param name   the name

-     */

-    public ConstructorCodeAdapter(final MethodVisitor mv, final String owner, Set<String> fields, int access, String name, String desc, String superClass) {

-        super(mv, access, name, desc);

-        m_owner = owner;

-        m_superDetected = false;

-        m_fields = fields;

-        m_superClass = superClass;

-    }

-

-    /**

-     * 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);

-        }

-    }

-

-    /**

-     * Visits a parameter annotation.

-     * Parameter annotations are moved to replacing constructor except

-     * they are injection annotations(-@Property and -@Requires).

-     * Because injection annotations shouldn't be copied to generated one

-     * in case of re-manipulation, since this is caused to wrong type resolution

-     * of injected parameters.

-     *

-     * @param parameter parameter index

-     * @param desc      annotation description(annotation name)

-     * @param visible   is parameter annotation visible

-     * @return @AnnotationVisitor

-     */

-    public AnnotationVisitor visitParameterAnnotation(

-            final int parameter,

-            final String desc,

-            final boolean visible) {

-

-        /*

-         * Generated constructor shouldn't inherit injection annotations

-         */

-        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Property;")

-                || desc.equals("Lorg/apache/felix/ipojo/annotations/Requires;")

-                || CustomAnnotationVisitor.isCustomAnnotation(desc)) {

-            return null;

-        } else {

-            return super.visitParameterAnnotation(parameter, desc, visible);

-        }

-

-    }

-

-

-    /**

-     * Adapts field accesses.

-     * If the field is owned by the visited class:

-     * <ul>

-     * <li><code>GETFIELD</code> are changed to a <code>__getX</code> invocation.</li>

-     * <li><code>SETFIELD</code> are changed to a <code>__setX</code> invocation.</li>

-     * </ul>

-     *

-     * @param opcode the visited operation code

-     * @param owner  the owner of the field

-     * @param name   the name of the field

-     * @param desc   the descriptor of the field

-     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)

-     */

-    public void visitFieldInsn(

-            final int opcode,

-            final String owner,

-            final String name,

-            final String desc) {

-        if (m_fields.contains(name) && m_owner.equals(owner)) {

-            if (opcode == GETFIELD) {

-                String gDesc = "()" + desc;

-                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);

-                return;

-            } else if (opcode == PUTFIELD) {

-                String sDesc = "(" + desc + ")V";

-                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);

-                return;

-            }

-        }

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

-    }

-

-    /**

-     * Visits a method invocation instruction.

-     * After the super constructor invocation, insert the _setComponentManager invocation.

-     * Otherwise, the method invocation doesn't change

-     *

-     * @param opcode the opcode

-     * @param owner  the class owning the invoked method

-     * @param name   the method name

-     * @param desc   the method descriptor

-     * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)

-     */

-    public void visitMethodInsn(int opcode, String owner, String name, String desc) {

-

-        // A method call is detected, check if it is the super call :

-        // the first init is not necessary the super call, so check that it is really the super class.

-        if (!m_superDetected && name.equals("<init>") && owner.equals(m_superClass)) {

-            m_superDetected = true;

-            // The first invocation is the super call

-            // 1) Visit the super constructor :

-

-            //mv.visitVarInsn(ALOAD, 0); The ALOAD 0 was already visited. This previous visit allows

-            // Super constructor parameters.

-            mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor invocation

-

-            // 2) Load the object and the component manager argument

-            mv.visitVarInsn(ALOAD, 0);

-            //mv.visitVarInsn(ALOAD, Type.getArgumentTypes(m_constructorDesc).length);

-            mv.visitVarInsn(ALOAD, 1);  // CM is always the first argument

-            // 3) Initialize the field

-            mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setInstanceManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V");

-

-        } else {

-            mv.visitMethodInsn(opcode, owner, name, desc);

-        }

-    }

-

-    /**

-     * Visits a variable instruction.

-     * This method increments the variable index if

-     * it is not <code>this</code> (i.e. 0). This increment

-     * is due to the instance manager parameter added in the method

-     * signature.

-     *

-     * @param opcode the opcode

-     * @param var    the variable index

-     * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)

-     */

-    public void visitVarInsn(int opcode, int var) {

-        if (var == 0) {

-            mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)

-        } else {

-            mv.visitVarInsn(opcode, var + 1); // All other variable index must be incremented (due to

-            // the instance manager argument

-        }

-

-    }

-

-    /**

-     * Visits an increment instruction.

-     * This method increments the variable index if

-     * it is not <code>this</code> (i.e. 0). This increment

-     * is due to the instance manager parameter added in the method

-     * signature.

-     *

-     * @param var       the variable index

-     * @param increment the increment

-     * @see org.objectweb.asm.MethodAdapter#visitIincInsn(int, int)

-     */

-    public void visitIincInsn(int var, int increment) {

-        if (var != 0) {

-            mv.visitIincInsn(var + 1, increment);

-        } else {

-            mv.visitIincInsn(var, increment); // Increment the current object ???

-        }

-    }

-

-    /**

-     * Visits a local variable.

-     * Adds _manager and increment others variable indexes.

-     * This variable has the same scope than <code>this</code> and

-     * has the <code>1</code> index.

-     *

-     * @param name      the variable name

-     * @param desc      the variable descriptor

-     * @param signature the variable signature

-     * @param start     the beginning label

-     * @param end       the ending label

-     * @param index     the variable index

-     * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)

-     */

-    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {

-        if (index == 0) {

-            mv.visitLocalVariable(name, desc, signature, start, end, index);

-            mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);

-        } else {

-            mv.visitLocalVariable(name, desc, signature, start, end, index + 1);

-        }

-    }

-

-    /**

-     * Visit max method.

-     * The stack size is incremented of 1. The

-     * local variable count is incremented of 2.

-     *

-     * @param maxStack  the stack size.

-     * @param maxLocals the local variable count.

-     * @see org.objectweb.asm.MethodAdapter#visitMaxs(int, int)

-     */

-    public void visitMaxs(int maxStack, int maxLocals) {

-        mv.visitMaxs(maxStack + 1, maxLocals + 2);

-    }

-

-}

+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulation;
+
+import java.util.Set;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.GeneratorAdapter;
+
+
+/**
+ * Constructor Adapter.
+ * This class adds an instance manager argument (so switch variable index).
+ * Moreover, it adapts field accesses to delegate accesses to the instance
+ * manager if needed.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {
+
+    /**
+     * The class containing the field.
+     * m_owner : String
+     */
+    private String m_owner;
+
+    /**
+     * Is the super call detected ?
+     */
+    private boolean m_superDetected;
+
+    /**
+     * The super class.
+     */
+    private String m_superClass;
+
+    /**
+     * Set of contained fields.
+     */
+    private Set<String> m_fields;
+
+
+    /**
+     * PropertyCodeAdapter constructor.
+     * A new FiledCodeAdapter should be create for each method visit.
+     *
+     * @param mv     the MethodVisitor
+     * @param owner  the name of the class
+     * @param fields the list of contained fields
+     * @param access the constructor access
+     * @param desc   the constructor descriptor
+     * @param name   the name
+     */
+    public ConstructorCodeAdapter(final MethodVisitor mv, final String owner, Set<String> fields, int access, String name, String desc, String superClass) {
+        super(mv, access, name, desc);
+        m_owner = owner;
+        m_superDetected = false;
+        m_fields = fields;
+        m_superClass = superClass;
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    /**
+     * Visits a parameter annotation.
+     * Parameter annotations are moved to replacing constructor except
+     * they are injection annotations(-@Property and -@Requires).
+     * Because injection annotations shouldn't be copied to generated one
+     * in case of re-manipulation, since this is caused to wrong type resolution
+     * of injected parameters.
+     *
+     * @param parameter parameter index
+     * @param desc      annotation description(annotation name)
+     * @param visible   is parameter annotation visible
+     * @return @AnnotationVisitor
+     */
+    public AnnotationVisitor visitParameterAnnotation(
+            final int parameter,
+            final String desc,
+            final boolean visible) {
+
+        /*
+         * Generated constructor shouldn't inherit injection annotations
+         */
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Property;")
+                || desc.equals("Lorg/apache/felix/ipojo/annotations/Requires;")
+                || Names.isCustomAnnotation(desc)) {
+            return null;
+        } else {
+            return super.visitParameterAnnotation(parameter, desc, visible);
+        }
+
+    }
+
+
+    /**
+     * Adapts field accesses.
+     * If the field is owned by the visited class:
+     * <ul>
+     * <li><code>GETFIELD</code> are changed to a <code>__getX</code> invocation.</li>
+     * <li><code>SETFIELD</code> are changed to a <code>__setX</code> invocation.</li>
+     * </ul>
+     *
+     * @param opcode the visited operation code
+     * @param owner  the owner of the field
+     * @param name   the name of the field
+     * @param desc   the descriptor of the field
+     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)
+     */
+    public void visitFieldInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc) {
+        if (m_fields.contains(name) && m_owner.equals(owner)) {
+            if (opcode == GETFIELD) {
+                String gDesc = "()" + desc;
+                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);
+                return;
+            } else if (opcode == PUTFIELD) {
+                String sDesc = "(" + desc + ")V";
+                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);
+                return;
+            }
+        }
+        super.visitFieldInsn(opcode, owner, name, desc);
+    }
+
+    /**
+     * Visits a method invocation instruction.
+     * After the super constructor invocation, insert the _setComponentManager invocation.
+     * Otherwise, the method invocation doesn't change
+     *
+     * @param opcode the opcode
+     * @param owner  the class owning the invoked method
+     * @param name   the method name
+     * @param desc   the method descriptor
+     * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
+     */
+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+
+        // A method call is detected, check if it is the super call :
+        // the first init is not necessary the super call, so check that it is really the super class.
+        if (!m_superDetected && name.equals("<init>") && owner.equals(m_superClass)) {
+            m_superDetected = true;
+            // The first invocation is the super call
+            // 1) Visit the super constructor :
+
+            //mv.visitVarInsn(ALOAD, 0); The ALOAD 0 was already visited. This previous visit allows
+            // Super constructor parameters.
+            mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor invocation
+
+            // 2) Load the object and the component manager argument
+            mv.visitVarInsn(ALOAD, 0);
+            //mv.visitVarInsn(ALOAD, Type.getArgumentTypes(m_constructorDesc).length);
+            mv.visitVarInsn(ALOAD, 1);  // CM is always the first argument
+            // 3) Initialize the field
+            mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setInstanceManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V");
+
+        } else {
+            mv.visitMethodInsn(opcode, owner, name, desc);
+        }
+    }
+
+    /**
+     * Visits a variable instruction.
+     * This method increments the variable index if
+     * it is not <code>this</code> (i.e. 0). This increment
+     * is due to the instance manager parameter added in the method
+     * signature.
+     *
+     * @param opcode the opcode
+     * @param var    the variable index
+     * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
+     */
+    public void visitVarInsn(int opcode, int var) {
+        if (var == 0) {
+            mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)
+        } else {
+            mv.visitVarInsn(opcode, var + 1); // All other variable index must be incremented (due to
+            // the instance manager argument
+        }
+
+    }
+
+    /**
+     * Visits an increment instruction.
+     * This method increments the variable index if
+     * it is not <code>this</code> (i.e. 0). This increment
+     * is due to the instance manager parameter added in the method
+     * signature.
+     *
+     * @param var       the variable index
+     * @param increment the increment
+     * @see org.objectweb.asm.MethodAdapter#visitIincInsn(int, int)
+     */
+    public void visitIincInsn(int var, int increment) {
+        if (var != 0) {
+            mv.visitIincInsn(var + 1, increment);
+        } else {
+            mv.visitIincInsn(var, increment); // Increment the current object ???
+        }
+    }
+
+    /**
+     * Visits a local variable.
+     * Adds _manager and increment others variable indexes.
+     * This variable has the same scope than <code>this</code> and
+     * has the <code>1</code> index.
+     *
+     * @param name      the variable name
+     * @param desc      the variable descriptor
+     * @param signature the variable signature
+     * @param start     the beginning label
+     * @param end       the ending label
+     * @param index     the variable index
+     * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)
+     */
+    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+        if (index == 0) {
+            mv.visitLocalVariable(name, desc, signature, start, end, index);
+            mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);
+        } else {
+            mv.visitLocalVariable(name, desc, signature, start, end, index + 1);
+        }
+    }
+
+    /**
+     * Visit max method.
+     * The stack size is incremented of 1. The
+     * local variable count is incremented of 2.
+     *
+     * @param maxStack  the stack size.
+     * @param maxLocals the local variable count.
+     * @see org.objectweb.asm.MethodAdapter#visitMaxs(int, int)
+     */
+    public void visitMaxs(int maxStack, int maxLocals) {
+        mv.visitMaxs(maxStack + 1, maxLocals + 2);
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
index 398f0d7..dea3ca1 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
@@ -22,14 +22,17 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
 import org.apache.felix.ipojo.manipulator.MetadataProvider;
 import org.apache.felix.ipojo.manipulator.Reporter;
 import org.apache.felix.ipojo.manipulator.ResourceStore;
 import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ClassMetadataCollector;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
 import org.apache.felix.ipojo.metadata.Element;
 import org.objectweb.asm.ClassReader;
 
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Bindings.newBindingRegistry;
+
 /**
  * A {@code AnnotationMetadataProvider} loads iPOJO metadata from bytecode of classes.
  *
@@ -40,10 +43,18 @@
     private ResourceStore m_store;
 
     private Reporter m_reporter;
+    private BindingRegistry m_registry;
 
     public AnnotationMetadataProvider(final ResourceStore store,
                                       final Reporter reporter) {
+        this(store, newBindingRegistry(reporter), reporter);
+    }
+
+    public AnnotationMetadataProvider(final ResourceStore store,
+                                      final BindingRegistry registry,
+                                      final Reporter reporter) {
         this.m_store = store;
+        this.m_registry = registry;
         this.m_reporter = reporter;
     }
 
@@ -61,15 +72,15 @@
                     try {
                         data = m_store.read(name);
                     } catch (IOException e) {
-                        m_reporter.warn("Cannot read content of " + name);
+                        m_reporter.warn("Cannot read content of %s", name);
                     }
 
                     // We check the array size to avoid manipulating empty files
                     // produced by incremental compilers (like Eclipse Compiler)
                     if (data != null && data.length > 0) {
-                        computeAnnotations(data, metadata);
+                        computeAnnotations(name, data, metadata);
                     } else {
-                        m_reporter.error("Cannot compute annotations from " + name + " : Empty file");
+                        m_reporter.error("Cannot compute annotations from %s : Empty file", name);
                     }
                 }
             }
@@ -80,27 +91,24 @@
 
     /**
      * Parse the content of the class to detect annotated classes.
-     * @param bytecode the class to inspect.
-     * @param metadata
+     * @param name Resource's name
+     * @param bytecode the class' content to inspect.
+     * @param metadata list of metadata to be filled
      */
-    private void computeAnnotations(byte[] bytecode, List<Element> metadata) {
+    private void computeAnnotations(String name, byte[] bytecode, List<Element> metadata) {
 
         ClassReader cr = new ClassReader(bytecode);
-        MetadataCollector collector = new MetadataCollector();
+        ClassMetadataCollector collector = new ClassMetadataCollector(m_registry, m_reporter);
         cr.accept(collector, 0);
 
-        if (collector.isIgnoredBecauseOfMissingComponent()) {
-            // No @Component, just skip.
-            //warn("Annotation processing ignored in " + collector.getClassName() + " - @Component missing");
-        } else if (collector.isComponentType()) {
-
-            // if no metadata or empty one, create a new array.
-            metadata.add(collector.getComponentTypeDeclaration());
+        if (collector.getComponentMetadata() != null) {
+            metadata.add(collector.getComponentMetadata());
 
             // Instantiate ?
-            if (collector.getInstanceDeclaration() != null) {
-                //warn("Declaring an empty instance of " + elem.getAttribute("classname"));
-                metadata.add(collector.getInstanceDeclaration());
+            Element instance = collector.getInstanceMetadata();
+            if (instance != null) {
+                m_reporter.trace("Declaring an empty instance of %s", instance.getAttribute("component"));
+                metadata.add(instance);
             }
         }
     }