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;
- }
-}
-