You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2013/09/30 20:32:26 UTC

svn commit: r1527700 - in /felix/trunk/ipojo/manipulator/manipulator/src: main/java/org/apache/felix/ipojo/manipulation/ main/java/org/apache/felix/ipojo/manipulator/ test/java/org/apache/felix/ipojo/manipulation/ test/java/test/inner/

Author: clement
Date: Mon Sep 30 18:32:25 2013
New Revision: 1527700

URL: http://svn.apache.org/r1527700
Log:
Start working on FELIX-4253 Add methods from inner classes in the metadata collected during the manipulation

Inner classes are added to the manipulation part of the metadata.

Modified:
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
    felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java
    felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java Mon Sep 30 18:32:25 2013
@@ -19,10 +19,8 @@
 
 package org.apache.felix.ipojo.manipulation;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
+import java.util.*;
+
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
@@ -72,7 +70,7 @@ public class ClassChecker extends EmptyV
     /**
      * List of visited inner class owned by the implementation class.
      */
-    private List<String> m_inners = new ArrayList<String>();
+    private Map<String, List<MethodDescriptor>> m_inners = new LinkedHashMap<String, List<MethodDescriptor>>();
 
     /**
      * <code>true</code> if the class supports annotations.
@@ -150,7 +148,7 @@ public class ClassChecker extends EmptyV
         if (m_className.equals(outerName)  || outerName == null) { // Anonymous classes does not have an outer class.
             // Do not include inner static class
             if (! ((access & ACC_STATIC) == ACC_STATIC)) {
-                m_inners.add(name);
+                m_inners.put(name, new ArrayList<MethodDescriptor>());
             }
         }
     }
@@ -237,17 +235,14 @@ public class ClassChecker extends EmptyV
         return null;
     }
 
-    private boolean isGeneratedConstructor(String name, String desc) {
+    public static boolean isGeneratedConstructor(String name, String desc) {
         return ("<init>".equals(name) && isFirstArgumentInstanceManager(desc));
     }
 
-    private boolean isFirstArgumentInstanceManager(String desc) {
+    public static boolean isFirstArgumentInstanceManager(String desc) {
         Type[] types = Type.getArgumentTypes(desc);
-        if (types != null && (types.length >= 1)) {
-            return Type.getType("Lorg/apache/felix/ipojo/InstanceManager;")
-                            .equals(types[0]);
-        }
-        return false;
+        return types != null && (types.length >= 1)
+                && Type.getType("Lorg/apache/felix/ipojo/InstanceManager;").equals(types[0]);
     }
 
     private boolean isGeneratedMethod(String name, String desc) {
@@ -315,10 +310,18 @@ public class ClassChecker extends EmptyV
         return m_superClass;
     }
 
-    public List<String> getInnerClasses() {
+    public Collection<String> getInnerClasses() {
+        return m_inners.keySet();
+    }
+
+    public Map<String, List<MethodDescriptor>> getInnerClassesAndMethods() {
         return m_inners;
     }
 
+    public String getClassName() {
+        return m_className;
+    }
+
     /**
      * This class collects annotations in a method.
      * This class creates an {@link AnnotationDescriptor}

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java Mon Sep 30 18:32:25 2013
@@ -33,6 +33,8 @@ import java.util.Set;
  */
 public class InnerClassAdapter extends ClassAdapter implements Opcodes {
 
+    private final Manipulator m_manipulator;
+    private final String m_name;
     /**
      * Implementation class name.
      */
@@ -45,14 +47,19 @@ public class InnerClassAdapter extends C
     /**
      * Creates the inner class adapter.
      *
+     * @param name      the inner class name
      * @param arg0       parent class visitor
      * @param outerClass outer class (implementation class)
      * @param fields     fields of the implementation class
+     * @param manipulator the manipulator having manipulated the outer class.
      */
-    public InnerClassAdapter(ClassVisitor arg0, String outerClass, Set<String> fields) {
+    public InnerClassAdapter(String name, ClassVisitor arg0, String outerClass, Set<String> fields,
+                             Manipulator manipulator) {
         super(arg0);
+        m_name = name;
         m_outer = outerClass;
         m_fields = fields;
+        m_manipulator = manipulator;
     }
 
     /**
@@ -68,8 +75,9 @@ public class InnerClassAdapter extends C
      * @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) {
-        // For non static and non constructor method, generate the wrapping method and move the method content within
-        // the manipulated method.
+
+        final MethodDescriptor md = new MethodDescriptor(name, desc, (access & ACC_STATIC) == ACC_STATIC);
+        m_manipulator.addMethodToInnerClass(m_name, md);
 
         // Do nothing on static methods, should not happen in non-static inner classes.
         if ((access & ACC_STATIC) == ACC_STATIC) {
@@ -82,7 +90,12 @@ public class InnerClassAdapter extends C
         }
 
         MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-        return new MethodCodeAdapter(mv, m_outer, access, name, desc, m_fields);
+        if (! m_manipulator.isAlreadyManipulated()) {
+            // Do not re-manipulate.
+            return new MethodCodeAdapter(mv, m_outer, access, name, desc, m_fields);
+        } else {
+            return mv;
+        }
     }
 
 

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java Mon Sep 30 18:32:25 2013
@@ -36,6 +36,12 @@ import org.objectweb.asm.Opcodes;
 public class InnerClassManipulator {
 
     /**
+     * The manipulator having manipulated the component class.
+     */
+    private final Manipulator m_manipulator;
+    private final String m_innerClassName;
+
+    /**
      * Outer class class name.
      */
     private String m_outer;
@@ -47,12 +53,14 @@ public class InnerClassManipulator {
 
     /**
      * Creates an inner class manipulator.
-     * @param classname : class name
-     * @param fields : fields
+     * @param outerclassName : class name
+     * @param manipulator : fields
      */
-    public InnerClassManipulator(String classname, Set<String> fields) {
-        m_outer = classname;
-        m_fields = fields;
+    public InnerClassManipulator(String innerClassName, String outerclassName, Manipulator manipulator) {
+        m_outer = outerclassName;
+        m_innerClassName = innerClassName;
+        m_fields = manipulator.getFields().keySet();
+        m_manipulator = manipulator;
     }
 
     /**
@@ -66,7 +74,7 @@ public class InnerClassManipulator {
 
         ClassReader cr = new ClassReader(is1);
         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-        InnerClassAdapter adapter = new InnerClassAdapter(cw, m_outer, m_fields);
+        InnerClassAdapter adapter = new InnerClassAdapter(m_innerClassName, cw, m_outer, m_fields, m_manipulator);
         if (version >= Opcodes.V1_6) {
             cr.accept(adapter, ClassReader.EXPAND_FRAMES);
         } else {

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java Mon Sep 30 18:32:25 2013
@@ -19,19 +19,17 @@
 
 package org.apache.felix.ipojo.manipulation;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Opcodes;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
 /**
  * iPOJO Byte code Manipulator.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
@@ -59,9 +57,9 @@ public class Manipulator {
     private String m_superClass;
 
     /**
-     * List of owned inner classed.
+     * List of owned inner classes and internal methods.
      */
-    private List<String> m_inners;
+    private Map<String, List<MethodDescriptor>> m_inners;
 
     /**
      * Java byte code version.
@@ -69,6 +67,16 @@ public class Manipulator {
     private int m_version;
 
     /**
+     * Was the class already manipulated.
+     */
+    private boolean m_alreadyManipulated;
+
+    /**
+     * The manipulated class name.
+     */
+    private String m_className;
+
+    /**
      * Manipulate the given byte array.
      * @param origin : original class.
      * @return the manipulated class, if the class is already manipulated, the original class.
@@ -84,6 +92,7 @@ public class Manipulator {
         is1.close();
 
         m_fields = ck.getFields(); // Get visited fields (contains only POJO fields)
+        m_className = ck.getClassName();
 
         // Get interfaces and super class.
         m_interfaces = ck.getInterfaces();
@@ -92,12 +101,15 @@ public class Manipulator {
         // Get the methods list
         m_methods = ck.getMethods();
 
-        m_inners = ck.getInnerClasses();
+        m_inners = ck.getInnerClassesAndMethods();
 
         m_version = ck.getClassVersion();
 
         ClassWriter finalWriter = null;
-        if (!ck.isAlreadyManipulated()) {
+
+        m_alreadyManipulated = ck.isAlreadyManipulated();
+
+        if (!m_alreadyManipulated) {
             // Manipulation ->
             // Add the _setComponentManager method
             // Instrument all fields
@@ -105,17 +117,17 @@ public class Manipulator {
             ClassReader cr0 = new ClassReader(is2);
             ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
             //CheckClassAdapter ch = new CheckClassAdapter(cw0);
-            MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);
+            MethodCreator process = new MethodCreator(cw0, m_fields, m_methods);
             if (ck.getClassVersion() >= Opcodes.V1_6) {
-                cr0.accept(preprocess, ClassReader.EXPAND_FRAMES);
+                cr0.accept(process, ClassReader.EXPAND_FRAMES);
             } else {
-                cr0.accept(preprocess, 0);
+                cr0.accept(process, 0);
             }
             is2.close();
             finalWriter = cw0;
         }
         // The file is in the bundle
-        if (ck.isAlreadyManipulated()) {
+        if (m_alreadyManipulated) {
             return origin;
         } else {
             return finalWriter.toByteArray();
@@ -123,51 +135,100 @@ public class Manipulator {
     }
 
     /**
+     * Checks whether the class was already manipulated.
+     * @return {@code true} if the class was already manipulated, {@code false} otherwise
+     */
+    public boolean isAlreadyManipulated() {
+        return m_alreadyManipulated;
+    }
+
+    public static String toQualifiedName(String clazz) {
+        return clazz.replace("/", ".");
+    }
+
+    /**
      * Compute component type manipulation metadata.
      * @return the manipulation metadata of the class.
      */
     public Element getManipulationMetadata() {
         Element elem = new Element("Manipulation", "");
 
+        elem.addAttribute(new Attribute("className", toQualifiedName(m_className)));
+
         if (m_superClass != null) {
             elem.addAttribute(new Attribute("super", m_superClass));
         }
 
-        for (int j = 0; j < m_interfaces.size(); j++) {
+        for (String m_interface : m_interfaces) {
             Element itf = new Element("Interface", "");
-            Attribute att = new Attribute("name", m_interfaces.get(j).toString());
+            Attribute att = new Attribute("name", m_interface);
             itf.addAttribute(att);
             elem.addElement(itf);
         }
 
-        for (Iterator<String> it = m_fields.keySet().iterator(); it.hasNext();) {
+        for (Map.Entry<String, String> f : m_fields.entrySet()) {
             Element field = new Element("Field", "");
-            String name = it.next();
-            String type = m_fields.get(name);
-            Attribute attName = new Attribute("name", name);
-            Attribute attType = new Attribute("type", type);
+            Attribute attName = new Attribute("name", f.getKey());
+            Attribute attType = new Attribute("type", f.getValue());
             field.addAttribute(attName);
             field.addAttribute(attType);
             elem.addElement(field);
         }
 
-        for (int j = 0; j < m_methods.size(); j++) {
-            MethodDescriptor method = (MethodDescriptor) m_methods.get(j);
+        for (MethodDescriptor method : m_methods) {
             elem.addElement(method.getElement());
         }
 
+        for (Map.Entry<String, List<MethodDescriptor>> inner : m_inners.entrySet()) {
+            Element element = new Element("Inner", "");
+            Attribute name = new Attribute("name", extractInnerClassName(toQualifiedName(inner.getKey())));
+            element.addAttribute(name);
+
+            for (MethodDescriptor method : inner.getValue()) {
+                element.addElement(method.getElement());
+            }
+            elem.addElement(element);
+        }
+
         return elem;
     }
 
+    /**
+     * Extracts the inner class simple name from the qualified name. It extracts the part after the `$` character.
+     * @param clazz the qualified class name
+     * @return the simple inner class name
+     */
+    public static String extractInnerClassName(String clazz) {
+        if (!clazz.contains("$")) {
+            return clazz;
+        } else {
+            return clazz.substring(clazz.indexOf("$") +1);
+        }
+    }
+
     public Map<String, String> getFields() {
         return m_fields;
     }
 
-    public List<String> getInnerClasses() {
-        return m_inners;
+    public Collection<String> getInnerClasses() {
+        return new ArrayList<String>(m_inners.keySet());
     }
 
     public int getClassVersion() {
         return m_version;
     }
+
+    /**
+     * Adds a method to an inner class.
+     * @param name the inner class name
+     * @param md the method descriptor to add
+     */
+    public void addMethodToInnerClass(String name, MethodDescriptor md) {
+        List<MethodDescriptor> list = m_inners.get(name);
+        if (list == null) {
+            list = new ArrayList<MethodDescriptor>();
+            m_inners.put(name, list);
+        }
+        list.add(md);
+    }
 }

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java Mon Sep 30 18:32:25 2013
@@ -32,26 +32,25 @@ import org.objectweb.asm.tree.LocalVaria
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class MethodDescriptor {
-
     /**
      * Method name.
      */
-    private String m_name;
+    private final String m_name;
 
     /**
      * Returned type.
      */
-    private String m_returnType;
+    private final String m_returnType;
 
     /**
      * Argument types.
      */
-    private String[] m_arguments;
+    private final String[] m_arguments;
 
     /**
      * The descriptor of the method.
      */
-    private String m_desc;
+    private final String m_desc;
 
 
     /**

Modified: felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java Mon Sep 30 18:32:25 2013
@@ -111,7 +111,6 @@ public class ManipulationEngine {
                 try {
                     byte[] out = manipulator.manipulate(bytecode);
                     // Call the visitor
-                    result.visitClassStructure(manipulator.getManipulationMetadata());
                     result.visitManipulatedResource(info.getResourcePath(), out);
                 } catch (IOException e) {
                     m_reporter.error("Cannot manipulate the class " + info.getClassName() + " : " + e.getMessage());
@@ -137,7 +136,9 @@ public class ManipulationEngine {
                     // discovered in the main class instead of re-parsing the inner class to find
                     // its own class version
                     try {
-                        InnerClassManipulator innerManipulator = new InnerClassManipulator(outerClassInternalName, manipulator.getFields().keySet());
+                        InnerClassManipulator innerManipulator = new InnerClassManipulator(inner,
+                                outerClassInternalName,
+                                manipulator);
                         byte[] manipulated = innerManipulator.manipulate(innerClassBytecode, manipulator.getClassVersion());
                         // Propagate manipulated resource
                         result.visitManipulatedResource(resourcePath, manipulated);
@@ -147,6 +148,9 @@ public class ManipulationEngine {
                     }
                 }
 
+                // Compute manipulation metadata
+                result.visitClassStructure(manipulator.getManipulationMetadata());
+
                 // All resources have been manipulated for this component
                 result.visitEnd();
             }

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ClassCheckerTestCase.java Mon Sep 30 18:32:25 2013
@@ -21,6 +21,7 @@ package org.apache.felix.ipojo.manipulat
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -58,7 +59,7 @@ public class ClassCheckerTestCase extend
         assertNull(checker.getSuperClass());
 
         // Check inner classes
-        List<String> inner = checker.getInnerClasses();
+        Collection<String> inner = checker.getInnerClasses();
         assertTrue(inner.isEmpty());
 
         // Ensure fields are correctly filtered

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/InnerClassAdapterTest.java Mon Sep 30 18:32:25 2013
@@ -22,7 +22,7 @@ package org.apache.felix.ipojo.manipulat
 import junit.framework.Assert;
 import org.apache.felix.ipojo.InstanceManager;
 import org.apache.felix.ipojo.Pojo;
-import org.junit.Ignore;
+import org.apache.felix.ipojo.metadata.Element;
 import org.junit.Test;
 import org.mockito.Mockito;
 
@@ -55,7 +55,8 @@ public class InnerClassAdapterTest {
             byte[] innerClassBytecode = ManipulatorTest.getBytesFromFile(new File(baseClassDirectory + s + "" +
                     ".class"));
             String innerClassName = s.replace("/", ".");
-            InnerClassManipulator innerManipulator = new InnerClassManipulator(outerClassInternalName, manipulator.getFields().keySet());
+            InnerClassManipulator innerManipulator = new InnerClassManipulator(s, outerClassInternalName,
+                    manipulator);
             byte[] manipulated = innerManipulator.manipulate(innerClassBytecode, manipulator.getClassVersion());
             classloader.addInnerClass(innerClassName, manipulated);
         }
@@ -146,4 +147,96 @@ public class InnerClassAdapterTest {
         assertEquals(result, "foofoofoofoo");
     }
 
+    @Test
+    public void testRemanipulationOfInnerClasses() throws IOException, ClassNotFoundException, NoSuchMethodException,
+            IllegalAccessException, InvocationTargetException, InstantiationException {
+        Manipulator manipulator = new Manipulator();
+        String className = "test.inner.ComponentWithInnerClasses";
+
+        // Two manipulation of the outer class.
+        byte[] bytecode = manipulator.manipulate(ManipulatorTest.getBytesFromFile(new File
+                (baseClassDirectory + className.replace(".", "/") + ".class")));
+        bytecode = manipulator.manipulate(bytecode);
+
+        ManipulatedClassLoader classloader = new ManipulatedClassLoader(className, bytecode);
+
+        // Manipulate all inner classes
+        for (String s : manipulator.getInnerClasses()) {
+            String outerClassInternalName = className.replace(".", "/");
+            byte[] innerClassBytecode = ManipulatorTest.getBytesFromFile(new File(baseClassDirectory + s + "" +
+                    ".class"));
+            String innerClassName = s.replace("/", ".");
+            InnerClassManipulator innerManipulator = new InnerClassManipulator(s, outerClassInternalName,
+                    manipulator);
+            // Two manipulation of all inner classes.
+            byte[] manipulated = innerManipulator.manipulate(innerClassBytecode, manipulator.getClassVersion());
+            manipulated = innerManipulator.manipulate(manipulated, manipulator.getClassVersion());
+            classloader.addInnerClass(innerClassName, manipulated);
+        }
+
+        Class clazz = classloader.findClass(className);
+        Assert.assertNotNull(clazz);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+        Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+        // We should have found only 2 inner classes.
+        assertThat(manipulator.getInnerClasses().size()).isEqualTo(3);
+
+        // Check that all inner classes are manipulated.
+        InstanceManager im = Mockito.mock(InstanceManager.class);
+        Constructor constructor = clazz.getDeclaredConstructor(InstanceManager.class);
+        constructor.setAccessible(true);
+        Object pojo = constructor.newInstance(new Object[] {im});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+        Method method = clazz.getMethod("doSomething", new Class[0]);
+        String result = (String) method.invoke(pojo);
+        assertEquals(result, "foofoofoofoo");
+    }
+
+    @Test
+    public void testThatManipulationMetadataContainsTheInnerClasses() throws IOException, ClassNotFoundException,
+            NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+        Manipulator manipulator = new Manipulator();
+        String className = "test.inner.ComponentWithInnerClasses";
+        manipulate(className, manipulator);
+
+        assertThat(manipulator.getInnerClasses().size()).isEqualTo(3);
+
+        Element manipulation = manipulator.getManipulationMetadata();
+        System.out.println(manipulation);
+        Element[] inners = manipulation.getElements("inner");
+        assertThat(inners.length).isEqualTo(3);
+
+        Element inner = getInnerClassMetadataByName(inners, "MyInnerWithANativeMethod");
+        assertThat(inner).isNotNull();
+        assertThat(getMethodByName(inner.getElements("method"), "foo")).isNotNull();
+
+        inner = getInnerClassMetadataByName(inners, "MyInnerClass");
+        assertThat(inner).isNotNull();
+        assertThat(getMethodByName(inner.getElements("method"), "foo")).isNotNull();
+
+        inner = getInnerClassMetadataByName(inners, "1");
+        assertThat(inner).isNotNull();
+        assertThat(getMethodByName(inner.getElements("method"), "compute")).isNotNull();
+
+    }
+
+    private static Element getInnerClassMetadataByName(Element[] inners, String name) {
+        for (Element element : inners) {
+            if (name.equals(element.getAttribute("name"))) {
+                return element;
+            }
+        }
+        return null;
+    }
+
+    private static Element getMethodByName(Element[] methods, String name) {
+        for (Element element : methods) {
+            if (name.equals(element.getAttribute("name"))) {
+                return element;
+            }
+        }
+        return null;
+    }
+
 }

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/ComponentWithInnerClasses.java Mon Sep 30 18:32:25 2013
@@ -32,17 +32,19 @@ public class ComponentWithInnerClasses{
         MyInnerClass inn = new MyInnerClass();
         Computation compute = new Computation() {
 
-            public String compute() {
+            public String compute(final String s) {
                 return "foo";
             }
         };
-        return nat.foo() + MyStaticInnerClass.foo() + inn.foo() + compute.compute();
+        return nat.foo() + MyStaticInnerClass.foo() + inn.foo() + compute.compute("");
     }
 
+    private String foo = "foo";
+
     private class MyInnerWithANativeMethod {
 
         public String foo() {
-            return "foo";
+            return ComponentWithInnerClasses.this.foo;
         }
 
         public native void baz();
@@ -64,7 +66,7 @@ public class ComponentWithInnerClasses{
 
     private class MyInnerClass {
         public String foo() {
-            return "foo";
+            return ComponentWithInnerClasses.this.foo;
         }
     }
 

Modified: felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java?rev=1527700&r1=1527699&r2=1527700&view=diff
==============================================================================
--- felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java (original)
+++ felix/trunk/ipojo/manipulator/manipulator/src/test/java/test/inner/Computation.java Mon Sep 30 18:32:25 2013
@@ -24,5 +24,5 @@ package test.inner;
  */
 public interface Computation {
 
-    public String compute();
+    public String compute(String s);
 }