Integrate the constructor-injection branch into the trunk.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1052264 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/pom.xml b/ipojo/manipulator/pom.xml
index 5b0e68b..ea42af2 100644
--- a/ipojo/manipulator/pom.xml
+++ b/ipojo/manipulator/pom.xml
@@ -51,6 +51,11 @@
       <artifactId>org.apache.felix.ipojo.metadata</artifactId>
       <version>1.4.0</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+      <version>1.7.0-SNAPSHOT</version>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
@@ -109,6 +114,16 @@
           <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
         </configuration>
       </plugin>
+
+	<plugin>
+		<groupId>org.apache.maven.plugins</groupId>
+		<artifactId>maven-compiler-plugin</artifactId>
+		<configuration>
+			<source>1.5</source>
+			<target>1.5</target>
+		</configuration>
+	</plugin>
+
     </plugins>
 
     <resources>
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 41cca2f..7847464 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
@@ -191,15 +191,14 @@
             newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

 

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

+

+            // TODO HERE ! => All constructor matches, no distinction between the different constructors.

+            generateConstructor(access, desc, signature, exceptions, md.getAnnotations(), md.getParameterAnnotations());

+

             if (args.length == 0) {

-                generateEmptyConstructor(access, signature, exceptions, md.getAnnotations()); // No parameters, so no annotations parameters

                 m_foundSuitableConstructor = true;

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

-                generateBCConstructor(access, signature, exceptions, md.getAnnotations()); // One parameter, so no annotations parameters

                 m_foundSuitableConstructor = true;

-            } else {

-                // Do nothing, the constructor does not match.

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

             }

 

             // Insert the new constructor

@@ -297,64 +296,56 @@
     }

 

     /**

-     * Create a constructor to call the manipulated constructor.

-     * This constructor does not have any argument. It will call the manipulated

-     * constructor with a null instance manager.

+     * Modify the given constructor to be something like:

+     * <code>

+     * this(null, params...);

+     * return;

+     * </code>

+     * The actual constructor is modified to support the instance manager argument.

      * @param access : access flag

+     * @param descriptor : the original constructor descriptor

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

+    private void generateConstructor(int access, String descriptor, String signature, String[] exceptions, List annotations, Map paramAnnotations) {

+         GeneratorAdapter mv = new GeneratorAdapter(

+        		 cv.visitMethod(access, "<init>", descriptor, signature, exceptions),

+        		 access, "<init>", descriptor);

+    	 // Compute the new signature

+    	 String newDesc = descriptor.substring(1); // Remove the first (

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

 

-        // Move annotations

-        if (annotations != null) {

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

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

-                ad.visitAnnotation(mv);

-            }

-        }

+         mv.visitCode();

+         mv.visitVarInsn(ALOAD, 0);

+         mv.visitInsn(ACONST_NULL);

+         mv.loadArgs();

+         mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", newDesc);

+         mv.visitInsn(RETURN);

 

-        mv.visitMaxs(0, 0);

-        mv.visitEnd();

-    }

+         // Move annotations

+         if (annotations != null) {

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

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

+                 ad.visitAnnotation(mv);

+             }

+         }

 

-    /**

-     * Create a constructor to call the manipulated constructor.

-     * This constructor has one argument (the bundle context). It will call the manipulated

-     * constructor with a null instance manager.

-     * @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, List annotations) {

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

-        mv.visitCode();

-        Label l0 = new Label();

-        mv.visitLabel(l0);

-        mv.visitVarInsn(ALOAD, 0);

-        mv.visitInsn(ACONST_NULL);

-        mv.visitVarInsn(ALOAD, 1);

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

-        mv.visitInsn(RETURN);

+         // Move parameter annotations if any

+         if (paramAnnotations != null  && ! paramAnnotations.isEmpty()) {

+             Iterator ids = paramAnnotations.keySet().iterator();

+             while(ids.hasNext()) {

+                 Integer id = (Integer) ids.next();

+                 List ads = (List) paramAnnotations.get(id);

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

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

+                     ad.visitParameterAnnotation(id.intValue(), mv);

+                 }

+             }

+         }

 

-        // Move annotations

-        if (annotations != null) {

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

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

-                ad.visitAnnotation(mv);

-            }

-        }

-

-        mv.visitMaxs(0, 0);

-        mv.visitEnd();

+         mv.visitMaxs(0, 0);

+         mv.visitEnd();

     }

 

     /**

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 fdd3ba2..a5e9f45 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
@@ -1,4 +1,4 @@
-/* 

+/*

  * 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

@@ -23,6 +23,7 @@
 import org.apache.felix.ipojo.metadata.Attribute;

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

 import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.Type;

 import org.objectweb.asm.commons.EmptyVisitor;

 

 /**

@@ -31,8 +32,6 @@
  */

 public class CustomAnnotationVisitor extends EmptyVisitor implements AnnotationVisitor {

 

-    //TODO manage enum annotations.

-    

     /**

      * Parent element.

      */

@@ -54,7 +53,7 @@
      * Is the custom annotation a first-order annotation.

      */

     private boolean m_root;

-    

+

     /**

      * Is the visit annotation a class annotation?

      */

@@ -64,7 +63,22 @@
      * Metadata collector.

      */

     private MetadataCollector m_collector;

-    

+

+    /**

+     * Flag sets to true for parameter annotation.

+     */

+    private boolean m_isParameterAnnotation = false;

+

+    /**

+     * For parameter annotations, the index of the parameter.

+     */

+    private int m_index = -1;

+

+    /**

+     * For parameter annotation, the descriptor of the method.

+     */

+    private String m_desc;

+

     /**

      * Constructor.

      * @param elem the parent element

@@ -78,7 +92,26 @@
         m_collector = collector;

         m_classAnnotation = clazz;

     }

-    

+

+    /**

+     * Constructor used for parameter annotations

+     * @param elem the parent element

+     * @param collector the metadata collector

+     * @param root is the annotation a root

+     * @param clazz the annotation is a class annotation.

+     * @param index the index of the argument

+     * @param the descriptor of the method

+     */

+    public CustomAnnotationVisitor(Element elem, MetadataCollector collector, boolean root, boolean clazz, int index, String descriptor) {

+        m_elem = elem;

+        m_root = root;

+        m_collector = collector;

+        m_classAnnotation = clazz;

+        m_isParameterAnnotation = true;

+        m_index = index;

+        m_desc = descriptor;

+    }

+

     /**

      * Check if the given annotation descriptor is an iPOJO custom annotation.

      * A valid iPOJO custom annotation must contains 'ipojo' or 'handler' in its qualified name.

@@ -92,7 +125,7 @@
         }

         return false;

     }

-    

+

     /**

      * Build the element object from the given descriptor.

      * @param desc : annotation descriptor

@@ -109,7 +142,7 @@
 

     /**

      * Visit a 'simple' annotation attribute.

-     * This method is used for primitive arrays too. 

+     * This method is used for primitive arrays too.

      * @param arg0 : attribute name

      * @param arg1 : attribute value

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

@@ -164,7 +197,7 @@
     public AnnotationVisitor visitArray(String arg0) {

         return new SubArrayVisitor(m_elem, arg0);

     }

-    

+

     /**

      * Visits an enumeration attribute.

      * @param arg0 the attribute name

@@ -186,6 +219,7 @@
             if (m_id != null) {

                 m_collector.getIds().put(m_id, m_elem);

             } else {

+            	m_id = m_elem.getNameSpace();

                 if (! m_collector.getIds().containsKey(m_elem.getNameSpace()) && m_classAnnotation) {

                     // If the namespace is not already used, add the annotation as the

                     // root element of this namespace.

@@ -197,8 +231,15 @@
                     }

                 }

             }

-            

+

             m_collector.getElements().put(m_elem, m_parent);

+

+            if (m_isParameterAnnotation) {

+            	String t = Type.getArgumentTypes(m_desc)[m_index].getClassName();

+            	m_elem.addAttribute(new Attribute("type", t));

+            	m_elem.addAttribute(

+            			new Attribute("constructor-parameter", Integer.toString(m_index)));

+            }

         }

     }

 

diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
index f3a4836..7c54269 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
@@ -210,7 +210,7 @@
      * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
      */
     public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
-        return new MethodCollector(name, this);
+        return new MethodCollector(name, desc, this);
     }
 
     /**
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
index 770316a..13ced4c 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.ipojo.manipulation.annotations;
 
+import java.awt.image.renderable.ParameterBlock;
+
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.objectweb.asm.AnnotationVisitor;
@@ -41,16 +43,47 @@
     private String m_name;
 
     /**
+     * Method Descriptor.
+     */
+    private String m_descriptor;
+
+    /**
      * Constructor.
      * @param name : name of the method.
      * @param collector : parent collector.
      */
-    public MethodCollector(String name, MetadataCollector collector) {
+    public MethodCollector(String name, String descriptor, MetadataCollector collector) {
         m_collector = collector;
         m_name = name;
+        m_descriptor = descriptor;
     }
 
     /**
+     * Visit a parameter annotation.
+     * @see org.objectweb.asm.commons.EmptyVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
+     */
+    public AnnotationVisitor visitParameterAnnotation(int index, String annotation,
+			boolean visible) {
+    	if (m_name.equals("<init>")) {
+    		if (annotation.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
+                return processProperty(true, index);
+            }
+            if (annotation.equals("Lorg/apache/felix/ipojo/annotations/Requires;")) {
+                return new BindAnnotationParser(index);
+            }
+
+            if (CustomAnnotationVisitor.isCustomAnnotation(annotation)) {
+                Element elem = CustomAnnotationVisitor.buildElement(annotation);
+                elem.addAttribute(new Attribute("index", "" + index));
+                return new CustomAnnotationVisitor(elem, m_collector, true, false, index, m_descriptor);
+            }
+    	}
+    	return super.visitParameterAnnotation(index, annotation, visible);
+	}
+
+
+
+	/**
      * Visit method annotations.
      * @param arg0 : annotation name.
      * @param arg1 : is the annotation visible at runtime.
@@ -59,7 +92,7 @@
      */
     public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
         if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
-            return processProperty();
+            return processProperty(false, -1);
         }
         if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Validate;")) {
             return processValidate();
@@ -181,9 +214,11 @@
 
     /**
      * Process @property annotation.
+     * @param parameter true if we're processing a parameter
+     * @param index the index, meaningful only if parameter is true
      * @return the visitor parsing the visited annotation.
      */
-    private AnnotationVisitor processProperty() {
+    private AnnotationVisitor processProperty(boolean parameter, int index) {
         Element prop = null;
         if (! m_collector.getIds().containsKey("properties")) {
             prop = new Element("Properties", "");
@@ -192,7 +227,7 @@
         } else {
             prop = (Element) m_collector.getIds().get("properties");
         }
-        return new PropertyAnnotationParser(prop, m_name);
+        return new PropertyAnnotationParser(prop, m_name, parameter, index);
     }
 
     /**
@@ -251,6 +286,12 @@
         private String m_from;
 
         /**
+         * For annotation parameter,
+         * the parameter index.
+         */
+        private int m_index = -1;
+
+        /**
          * Constructor.
          * @param bind : method name.
          * @param type : is the callback a bind or an unbind method.
@@ -260,6 +301,10 @@
             m_type = type;
         }
 
+        private BindAnnotationParser(int index) {
+        	m_index = index;
+        }
+
         /**
          * Visit annotation attribute.
          * @param arg0 : annotation name
@@ -310,17 +355,20 @@
          */
         public void visitEnd() {
             if (m_id == null) {
-                if (m_name.startsWith("bind")) {
+                if (m_name != null  && m_name.startsWith("bind")) {
                     m_id = m_name.substring("bind".length());
-                } else if (m_name.startsWith("unbind")) {
+                } else if (m_name != null  && m_name.startsWith("unbind")) {
                     m_id = m_name.substring("unbind".length());
-                } else if (m_name.startsWith("modified")) {
+                } else if (m_name != null  && m_name.startsWith("modified")) {
                 	m_id = m_name.substring("modified".length());
-                } else {
+                } else if (m_index != -1) {
+                	m_id = "" + m_index;
+            	} else {
                     System.err.println("Cannot determine the id of the " + m_type + " method : " + m_name);
                     return;
                 }
             }
+
             // Check if it is a full-determined requirement
             Element req = (Element) m_collector.getIds().get(m_id);
             if (req == null) {
@@ -422,17 +470,22 @@
                 }
 
             }
-            Element method = new Element("callback", "");
-            method.addAttribute(new Attribute("method", m_name));
-            method.addAttribute(new Attribute("type", m_type));
-            req.addElement(method);
+            if (m_name != null) {
+	            Element method = new Element("callback", "");
+	            method.addAttribute(new Attribute("method", m_name));
+	            method.addAttribute(new Attribute("type", m_type));
+	            req.addElement(method);
+            } else {
+            	req.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+            }
+
             m_collector.getIds().put(m_id, req);
             m_collector.getElements().put(req, null);
             return;
         }
     }
 
-    private static final class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
+    private final class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
 
         /**
          * Parent element.
@@ -450,6 +503,11 @@
         private String m_name;
 
         /**
+         * Property id.
+         */
+        private String m_id;
+
+        /**
          * Property value.
          */
         private String m_value;
@@ -460,13 +518,27 @@
         private String m_mandatory;
 
         /**
+         * Flag set to true if we're processing an annotation parameter.
+         */
+        private boolean m_isParameterAnnotation = false;
+
+        /**
+         * If this is a parameter annotation, the index of the parameter.
+         */
+        private int m_index = -1;
+
+        /**
          * Constructor.
          * @param parent : parent element.
          * @param method : attached method.
+         * @param param : we're processing a parameter
+         * @param index : the parameter index
          */
-        private PropertyAnnotationParser(Element parent, String method) {
+        private PropertyAnnotationParser(Element parent, String method, boolean param, int index) {
             m_parent = parent;
             m_method = method;
+            m_isParameterAnnotation = param;
+            m_index = index;
         }
 
         /**
@@ -488,6 +560,10 @@
                 m_mandatory = arg1.toString();
                 return;
             }
+            if (arg0.equals("id")) {
+                m_id = arg1.toString();
+                return;
+            }
         }
 
         /**
@@ -496,9 +572,17 @@
          * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
          */
         public void visitEnd() {
-            if (m_name == null && m_method.startsWith("set")) {
+        	// If neither name not id, try to extract the name
+            if (m_name == null && m_id == null  && m_method.startsWith("set")) {
                 m_name = m_method.substring("set".length());
+                m_id = m_name;
+            // Else align the two values
+            } else if (m_name != null  && m_id == null) {
+            	m_id = m_name;
+            } else if (m_id != null  && m_name == null) {
+            	m_name = m_id;
             }
+
             Element[] props = m_parent.getElements("Property");
             Element prop = null;
             for (int i = 0; props != null && prop == null && i < props.length; i++) {
@@ -516,7 +600,6 @@
                 }
             }
 
-            prop.addAttribute(new Attribute("method", m_method));
             if (m_value != null) {
                 prop.addAttribute(new Attribute("value", m_value));
             }
@@ -524,6 +607,14 @@
                 prop.addAttribute(new Attribute("mandatory", m_mandatory));
             }
 
+            if (m_isParameterAnnotation) {
+            	String t = Type.getArgumentTypes(m_descriptor)[m_index].getClassName();
+            	prop.addAttribute(new Attribute("type", t));
+                prop.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+            } else {
+                prop.addAttribute(new Attribute("method", m_method));
+            }
+
         }
     }
 }
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
new file mode 100644
index 0000000..a81dea8
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
@@ -0,0 +1,12 @@
+package org.apache.felix.ipojo;
+
+
+/**
+ * Component Instance Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface ComponentInstance {
+
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
new file mode 100644
index 0000000..04281df
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
@@ -0,0 +1,20 @@
+package org.apache.felix.ipojo;
+
+import java.util.Set;
+
+/**
+ * Instance Manager Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public class InstanceManager {
+
+    public Set getRegistredFields() {
+        return null;
+    }
+
+    public Set getRegistredMethods() {
+        return null;
+    }
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
new file mode 100644
index 0000000..c7bcb59
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
@@ -0,0 +1,10 @@
+package org.apache.felix.ipojo;
+
+/**
+ * POJO Interface fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface Pojo {
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
new file mode 100644
index 0000000..03576b1
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
@@ -0,0 +1,335 @@
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Pojo;
+import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
+import org.mockito.Mockito;
+import org.objectweb.asm.ClassReader;
+
+public class ManipulatorTest extends TestCase {
+
+	public void testManipulatingTheSimplePojo() throws Exception {
+		Manipulator manipulator = new Manipulator();
+		byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")));
+		TestClassLoader classloader = new TestClassLoader("test.SimplePojo", clazz);
+		Class cl = classloader.findClass("test.SimplePojo");
+		Assert.assertNotNull(cl);
+		Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+		System.out.println(manipulator.getManipulationMetadata());
+
+		// The manipulation add stuff to the class.
+		Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")).length);
+
+
+		boolean found = false;
+		Constructor cst = null;
+		Constructor[] csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 1  &&
+					csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+				found = true;
+				cst = csts[i];
+			}
+		}
+		Assert.assertTrue(found);
+
+		// We still have the empty constructor
+		found = false;
+		csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 0) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+
+		// Check the POJO interface
+		Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+		cst.setAccessible(true);
+		Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+		Method method = cl.getMethod("doSomething", new Class[0]);
+		Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+	}
+
+	public void testManipulatingChild() throws Exception {
+		Manipulator manipulator = new Manipulator();
+		byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
+		TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+		Class cl = classloader.findClass("test.Child");
+		Assert.assertNotNull(cl);
+		Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+		boolean found = false;
+		Constructor cst = null;
+		Constructor[] csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 1  &&
+					csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+				found = true;
+				cst = csts[i];
+			}
+		}
+		Assert.assertTrue(found);
+
+		// We still have the regular constructor
+		found = false;
+		csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 2) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+
+		// Check the POJO interface
+		Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+		InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+		cst.setAccessible(true);
+		Object pojo = cst.newInstance(new Object[] {im});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+		Method method = cl.getMethod("doSomething", new Class[0]);
+		Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+	}
+
+	public void testManipulatingTheInner() throws Exception {
+		Manipulator manipulator = new Manipulator();
+		byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/PojoWithInner.class")));
+		TestClassLoader classloader = new TestClassLoader("test.PojoWithInner", clazz);
+		Class cl = classloader.findClass("test.PojoWithInner");
+		Assert.assertNotNull(cl);
+		Assert.assertNotNull(manipulator.getManipulationMetadata());
+		Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+
+
+		System.out.println(manipulator.getManipulationMetadata());
+
+		// The manipulation add stuff to the class.
+		Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/PojoWithInner.class")).length);
+
+
+		boolean found = false;
+		Constructor cst = null;
+		Constructor[] csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 1  &&
+					csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+				found = true;
+				cst = csts[i];
+			}
+		}
+		Assert.assertTrue(found);
+
+		// We still have the empty constructor
+		found = false;
+		csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 0) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+
+		// Check the POJO interface
+		Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+		InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+		cst.setAccessible(true);
+		Object pojo = cst.newInstance(new Object[] {im});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+		Method method = cl.getMethod("doSomething", new Class[0]);
+		Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+	}
+
+	public void testManipulatingWithConstructorModification() throws Exception {
+		Manipulator manipulator = new Manipulator();
+		byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
+		TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+		Class cl = classloader.findClass("test.Child");
+		Assert.assertNotNull(cl);
+		Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+		boolean found = false;
+		Constructor cst = null;
+		Constructor[] csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 1  &&
+					csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+				found = true;
+				cst = csts[i];
+			}
+		}
+		Assert.assertTrue(found);
+
+		// We still have the regular constructor
+		found = false;
+		csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 2) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+
+		// Check that we have the IM, Integer, String constructor too
+		Constructor cst2 = cl.getDeclaredConstructor(new Class[] { InstanceManager.class, Integer.TYPE, String.class });
+		Assert.assertNotNull(cst2);
+
+		// Check the POJO interface
+		Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+
+		// Creation using cst
+		InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+		cst.setAccessible(true);
+		Object pojo = cst.newInstance(new Object[] {im});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+		Method method = cl.getMethod("doSomething", new Class[0]);
+		Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+		// Try to create using cst2
+		im = (InstanceManager) Mockito.mock(InstanceManager.class);
+		cst2.setAccessible(true);
+		pojo = cst2.newInstance(new Object[] {im, new Integer(2), "bariton"});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+		method = cl.getMethod("doSomething", new Class[0]);
+		Assert.assertEquals(10, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+
+
+	}
+
+
+	public void testManipulatingWithNoValidConstructor() throws Exception {
+		Manipulator manipulator = new Manipulator();
+		byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")));
+		TestClassLoader classloader = new TestClassLoader("test.NoValidConstructor", clazz);
+		Class cl = classloader.findClass("test.NoValidConstructor");
+		Assert.assertNotNull(cl);
+		Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+		System.out.println(manipulator.getManipulationMetadata());
+
+		// The manipulation add stuff to the class.
+		Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")).length);
+
+
+		boolean found = false;
+		Constructor cst = null;
+		Constructor[] csts = cl.getDeclaredConstructors();
+		for (int i = 0; i < csts.length; i++) {
+			System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+			if (csts[i].getParameterTypes().length == 1  &&
+					csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+				found = true;
+				cst = csts[i];
+			}
+		}
+		Assert.assertTrue(found);
+
+		// Check the POJO interface
+		Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+		cst.setAccessible(true);
+		Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+		Assert.assertNotNull(pojo);
+		Assert.assertTrue(pojo instanceof Pojo);
+
+	}
+
+	public void test() throws Exception {
+
+
+		byte[] clazz = getBytesFromFile(new File("target/test-classes/test/Constructor.class"));
+		ClassReader cr = new ClassReader(clazz);
+        MetadataCollector collector = new MetadataCollector();
+        cr.accept(collector, 0);
+
+        System.out.println(collector.getComponentTypeDeclaration());
+
+	}
+
+	public static byte[] getBytesFromFile(File file) throws IOException {
+	    InputStream is = new FileInputStream(file);
+	    long length = file.length();
+	    byte[] bytes = new byte[(int)length];
+
+	    // Read in the bytes
+	    int offset = 0;
+	    int numRead = 0;
+	    while (offset < bytes.length
+	           && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+	        offset += numRead;
+	    }
+
+	    // Ensure all the bytes have been read in
+	    if (offset < bytes.length) {
+	        throw new IOException("Could not completely read file "+file.getName());
+	    }
+
+	    // Close the input stream and return bytes
+	    is.close();
+	    return bytes;
+	}
+
+	class TestClassLoader extends ClassLoader {
+
+		private String name;
+		private byte[] clazz;
+
+		public TestClassLoader(String name, byte[] clazz) {
+			this.name = name;
+			this.clazz = clazz;
+		}
+
+        public Class findClass(String name) throws ClassNotFoundException {
+        	if (name.equals(this.name)) {
+	            return defineClass(name, clazz, 0, clazz.length);
+        	}
+        	return super.findClass(name);
+        }
+
+		public Class loadClass(String arg0) throws ClassNotFoundException {
+			return super.loadClass(arg0);
+		}
+
+
+
+    }
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
new file mode 100644
index 0000000..68d4b5e
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
@@ -0,0 +1,43 @@
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.File;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+
+public class PojoizationTest extends TestCase {
+
+	public void testJarManipulation() {
+		Pojoization pojoization = new Pojoization();
+		File in = new File("target/test-classes/tests.manipulation-no-annotations.jar");
+		File out = new File("target/test-classes/tests.manipulation-no-annotations-manipulated.jar");
+		out.delete();
+		File metadata = new File("target/test-classes/metadata.xml");
+		pojoization.pojoization(in, out, metadata);
+
+		Assert.assertTrue(out.exists());
+	}
+
+	public void testManipulationWithAnnotations() {
+		Pojoization pojoization = new Pojoization();
+		File in = new File("target/test-classes/tests.manipulator-annotations.jar");
+		File out = new File("target/test-classes/tests.manipulation-annotations-manipulated.jar");
+		out.delete();
+		pojoization.pojoization(in, out, (File) null);
+
+		Assert.assertTrue(out.exists());
+	}
+
+	public void testJarManipulationJava5() {
+		Pojoization pojoization = new Pojoization();
+		File in = new File("target/test-classes/tests.manipulation.java5.jar");
+		File out = new File("target/test-classes/tests.manipulation.java5-manipulated.jar");
+		out.delete();
+		pojoization.pojoization(in, out, (File) null);
+
+		Assert.assertTrue(out.exists());
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/Child.java b/ipojo/manipulator/src/test/java/test/Child.java
new file mode 100644
index 0000000..1eda305
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/Child.java
@@ -0,0 +1,17 @@
+package test;
+
+public class Child extends Parent {
+
+	Child(int i, String f) {
+		super(i, f);
+	}
+
+	Child() {
+		super(5, "foo");
+	}
+
+	public int doSomething() {
+		return getIndex() + 1; // 9
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/Constructor.java b/ipojo/manipulator/src/test/java/test/Constructor.java
new file mode 100644
index 0000000..ccbaebe
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/Constructor.java
@@ -0,0 +1,15 @@
+package test;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Requires;
+
+@Component
+public class Constructor {
+
+	public Constructor(@Property(name="foo") String s, @Requires(id="t") Thread t) {
+		// plop
+
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/NoValidConstructor.java b/ipojo/manipulator/src/test/java/test/NoValidConstructor.java
new file mode 100644
index 0000000..45d52cb
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/NoValidConstructor.java
@@ -0,0 +1,15 @@
+package test;
+
+public class NoValidConstructor {
+
+	String m_s;
+
+	public NoValidConstructor(String s) {
+		m_s = s;
+	}
+
+	public String getS() {
+		return m_s;
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/Parent.java b/ipojo/manipulator/src/test/java/test/Parent.java
new file mode 100644
index 0000000..51ac622
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/Parent.java
@@ -0,0 +1,15 @@
+package test;
+
+public class Parent {
+
+	private int m_index = 0;
+
+	public Parent(int i, String s) {
+		m_index = i + s.length();
+	}
+
+	public int getIndex() {
+		return m_index;
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/PojoWithInner.java b/ipojo/manipulator/src/test/java/test/PojoWithInner.java
new file mode 100644
index 0000000..ac5a052
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/PojoWithInner.java
@@ -0,0 +1,21 @@
+package test;
+
+public class PojoWithInner {
+
+	private MyInner m_result = new MyInner();
+
+	// This is a simple POJO
+
+	public boolean doSomething() {
+		return m_result.getInner();
+	}
+
+	public class MyInner {
+
+		public boolean getInner() {
+			return true;
+		}
+
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/java/test/SimplePojo.java b/ipojo/manipulator/src/test/java/test/SimplePojo.java
new file mode 100644
index 0000000..3c1d6fa
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/SimplePojo.java
@@ -0,0 +1,13 @@
+package test;
+
+public class SimplePojo {
+
+	private boolean m_result = true;
+
+	// This is a simple POJO
+
+	public boolean doSomething() {
+		return m_result;
+	}
+
+}
diff --git a/ipojo/manipulator/src/test/resources/metadata.xml b/ipojo/manipulator/src/test/resources/metadata.xml
new file mode 100644
index 0000000..b3e0262
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/metadata.xml
@@ -0,0 +1,37 @@
+<ipojo

+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+    xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"

+    xmlns="org.apache.felix.ipojo"

+>

+	<!-- Simple provider  used for manipulation analysis -->

+	<component

+		classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

+		name="Manipulation-FooProviderType-1" architecture="true">

+		<provides />

+	</component>

+	

+	<!-- Non lazzy service provider, to check instantiation -->

+	<component

+		classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

+		name="Manipulation-ImmediateFooProviderType" immediate="true"

+		architecture="true">

+		<provides />

+	</component>

+	

+	<!-- Nested & Inner classes -->

+	<component name="inners" classname="org.apache.felix.ipojo.test.scenarios.component.InnerClasses">

+		<provides>

+			<property field="privateObject"/>

+			<property field="privateInt"/>

+			

+			<property field="protectedObject"/>

+			<property field="protectedInt"/>

+			

+			<property field="packageObject"/>

+			<property field="packageInt"/>

+			

+			<property field="publicObject"/>

+			<property field="publicInt"/>

+		</provides>

+	</component>

+</ipojo>

diff --git a/ipojo/manipulator/src/test/resources/tests.manipulation-no-annotations.jar b/ipojo/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
new file mode 100644
index 0000000..a701fc0
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
Binary files differ
diff --git a/ipojo/manipulator/src/test/resources/tests.manipulation.java5.jar b/ipojo/manipulator/src/test/resources/tests.manipulation.java5.jar
new file mode 100644
index 0000000..456e356
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/tests.manipulation.java5.jar
Binary files differ
diff --git a/ipojo/manipulator/src/test/resources/tests.manipulator-annotations.jar b/ipojo/manipulator/src/test/resources/tests.manipulator-annotations.jar
new file mode 100644
index 0000000..45322aa
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/tests.manipulator-annotations.jar
Binary files differ