To correctly compute the frames, we need a way to load classes - so a classloader. The manipulator now takes a classloader as parameter used for this purpose. (FELIX-4509).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1592767 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java
new file mode 100644
index 0000000..dc03688
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassLoaderAwareClassWriter.java
@@ -0,0 +1,92 @@
+/*
+ * 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 org.objectweb.asm.ClassWriter;
+
+/**
+ * An extension of {@link org.objectweb.asm.ClassWriter} that uses a specific classloader to load classes.
+ */
+public class ClassLoaderAwareClassWriter extends ClassWriter {
+
+    private static final String OBJECT_INTERNAL_NAME = "java/lang/Object";
+    private final String className;
+    private final String superClass;
+    private final ClassLoader classLoader;
+
+    public ClassLoaderAwareClassWriter(int flags, String className, String superClass, ClassLoader loader) {
+        super(flags);
+        this.className = className;
+        this.superClass = superClass;
+        this.classLoader = loader;
+    }
+
+    /**
+     * Implements the common super class lookup to be a bit more permissive. First we check is type1 == type2,
+     * because in this case, the lookup is done. Then, if one of the class is Object,
+     * returns object. If both checks failed, it returns Object.
+     *
+     * @param type1 the first class
+     * @param type2 the second class
+     * @return the common super class
+     */
+    @Override
+    protected final String getCommonSuperClass(String type1, String type2) {
+        //If the two are equal then return either
+        if (type1.equals(type2)) {
+            return type1;
+        }
+
+        //If either is Object, then Object must be the answer
+        if (type1.equals(OBJECT_INTERNAL_NAME) || type2.equals(OBJECT_INTERNAL_NAME)) {
+            return OBJECT_INTERNAL_NAME;
+        }
+
+        // If either of these class names are the current class then we can short
+        // circuit to the superclass (which we already know)
+        if (type1.equals(className.replace(".", "/")) && superClass != null) {
+            return getCommonSuperClass(superClass.replace(".", "/"), type2);
+        } else if (type2.equals(className.replace(".", "/")) && superClass != null)
+            return getCommonSuperClass(type1, superClass.replace(".", "/"));
+
+        Class<?> c, d;
+        try {
+            c = classLoader.loadClass(type1.replace('/', '.'));
+            d = classLoader.loadClass(type2.replace('/', '.'));
+        } catch (Exception e) {
+            throw new RuntimeException(e.toString());
+        }
+        if (c.isAssignableFrom(d)) {
+            return type1;
+        }
+        if (d.isAssignableFrom(c)) {
+            return type2;
+        }
+        if (c.isInterface() || d.isInterface()) {
+            return "java/lang/Object";
+        } else {
+            do {
+                c = c.getSuperclass();
+            } while (!c.isAssignableFrom(d));
+            return c.getName().replace('.', '/');
+        }
+    }
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
index e7ffe00..ba3a4e2 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -38,6 +38,10 @@
  */
 public class Manipulator {
     /**
+     * A classloader used to compute frames.
+     */
+    private final ClassLoader m_classLoader;
+    /**
      * Store the visited fields : [name of the field, type of the field].
      */
     private Map<String, String> m_fields;
@@ -77,6 +81,11 @@
      */
     private String m_className;
 
+    public Manipulator(ClassLoader loader) {
+        // No classloader set, use current one.
+        m_classLoader = loader;
+    }
+
     /**
      * Checks the given bytecode, determines if the class was already manipulated, and collect the metadata about the
      * class.
@@ -119,7 +128,8 @@
         if (!m_alreadyManipulated) {
             InputStream is2 = new ByteArrayInputStream(origin);
             ClassReader reader = new ClassReader(is2);
-            ClassWriter writer = new NoClassLoaderClassWriter(ClassWriter.COMPUTE_FRAMES);
+            ClassWriter writer = new ClassLoaderAwareClassWriter(ClassWriter.COMPUTE_FRAMES, m_className, m_superClass,
+                    m_classLoader);
             ClassManipulator process = new ClassManipulator(new CheckClassAdapter(writer, false), this);
             if (m_version >= Opcodes.V1_6) {
                 reader.accept(process, ClassReader.EXPAND_FRAMES);
@@ -262,7 +272,7 @@
             InputStream is1 = new ByteArrayInputStream(bytecode);
 
             ClassReader cr = new ClassReader(is1);
-            ClassWriter cw = new NoClassLoaderClassWriter(ClassWriter.COMPUTE_FRAMES);
+            ClassWriter cw = new ClassLoaderAwareClassWriter(ClassWriter.COMPUTE_FRAMES, inner, null, m_classLoader);
             InnerClassAdapter adapter = new InnerClassAdapter(inner, cw, m_className, this);
             if (m_version >= Opcodes.V1_6) {
                 cr.accept(adapter, ClassReader.EXPAND_FRAMES);
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/NoClassLoaderClassWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/NoClassLoaderClassWriter.java
deleted file mode 100644
index d24ed82..0000000
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/NoClassLoaderClassWriter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
-
-/**
- * An extension of {@link org.objectweb.asm.ClassWriter} that doe snot trigger class loading to compute the common super
- * class. It generally returns Object.
- */
-public class NoClassLoaderClassWriter extends ClassWriter {
-
-    private static final String OBJECT_INTERNAL_NAME = "java/lang/Object";
-
-    public NoClassLoaderClassWriter(ClassReader reader, int flags) {
-        super(reader, flags);
-    }
-
-    public NoClassLoaderClassWriter(int flags) {
-        super(flags);
-    }
-
-    /**
-     * Implements the common super class lookup to be a bit more permissive. First we check is type1 == type2,
-     * because in this case, the lookup is done. Then, if one of the class is Object,
-     * returns object. If both checks failed, it returns Object.
-     * @param type1 the first class
-     * @param type2 the second class
-     * @return the common super class
-     */
-    @Override
-    protected final String getCommonSuperClass(String type1, String type2) {
-        //If the two are equal then return either
-        if (type1.equals(type2)) {
-            return type1;
-        }
-
-        //If either is Object, then Object must be the answer
-        if (type1.equals(OBJECT_INTERNAL_NAME) || type2.equals(OBJECT_INTERNAL_NAME)) {
-            return OBJECT_INTERNAL_NAME;
-        }
-
-        // We shunt the rest of the process.
-        return OBJECT_INTERNAL_NAME;
-    }
-}
-