You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2014/06/19 09:01:32 UTC

svn commit: r1603727 - in /aries/trunk/proxy/proxy-impl/src: main/java/org/apache/aries/proxy/impl/ main/java/org/apache/aries/proxy/impl/gen/ test/java/org/apache/aries/blueprint/proxy/ test/java/org/apache/aries/proxy/test/ test/java/org/apache/aries...

Author: gnodet
Date: Thu Jun 19 07:01:32 2014
New Revision: 1603727

URL: http://svn.apache.org/r1603727
Log:
[ARIES-1216] Error when creating proxies with an invisible super class in the hierarchy

Added:
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
Modified:
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java?rev=1603727&r1=1603726&r2=1603727&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java Thu Jun 19 07:01:32 2014
@@ -18,13 +18,19 @@
  */
 package org.apache.aries.proxy.impl;
 
+import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
@@ -100,13 +106,100 @@ public final class AsmProxyManager exten
         }
       } 
       if(proxyObject == null){
-        proxyObject = ProxySubclassGenerator.newProxySubclassInstance(classToProxy, new ProxyHandler(this, dispatcher, listener));
+        // ARIES-1216 : in some cases, some class can not be visible from the root class classloader.
+        // If that's the case, we need to build a custom classloader that has visibility on all those classes
+        // If we could generate a proper constructor this would not be necessary, but since we have to rely
+        // on the generated serialization constructor to bypass the JVM verifier, we don't have much choice
+        ClassLoader classLoader = classToProxy.getClassLoader();
+        boolean allVisible = true;
+        for (Class<?> clazz : classes) {
+          try {
+            if (classLoader.loadClass(clazz.getName()) != clazz) {
+              throw new UnableToProxyException(classToProxy, "The requested class " + clazz + " is different from the one seen by by " + classToProxy);
+            }
+          } catch (ClassNotFoundException e) {
+            allVisible = false;
+            break;
+          }
+        }
+        if (!allVisible) {
+          List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
+          for (Class<?> clazz : classes) {
+            ClassLoader cl = clazz.getClassLoader();
+            if (cl != null && !classLoaders.contains(cl)) {
+              classLoaders.add(cl);
+            }
+          }
+          classLoader = new MultiClassLoader(classLoaders);
+        }
+        proxyObject = ProxySubclassGenerator.newProxySubclassInstance(classToProxy, classLoader, new ProxyHandler(this, dispatcher, listener));
       }
     }
 
     return proxyObject;
   }
 
+  private static class MultiClassLoader extends ClassLoader {
+    private final List<ClassLoader> parents;
+    private MultiClassLoader(List<ClassLoader> parents) {
+      this.parents = parents;
+    }
+
+    @Override
+    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+      for (ClassLoader cl : parents) {
+         try {
+           return cl.loadClass(name);
+         } catch (ClassNotFoundException e) {
+           // Ignore
+         }
+        }
+        throw new ClassNotFoundException(name);
+    }
+
+    @Override
+    public URL getResource(String name) {
+      for (ClassLoader cl : parents) {
+         URL url = cl.getResource(name);
+         if (url != null) {
+           return url;
+         }
+       }
+       return null;
+    }
+
+    @Override
+    public Enumeration<URL> getResources(String name) throws IOException {
+      final List<Enumeration<URL>> tmp = new ArrayList<Enumeration<URL>>();
+      for (ClassLoader cl : parents) {
+        tmp.add(cl.getResources(name));
+      }
+      return new Enumeration<URL>() {
+        int index = 0;
+        @Override
+        public boolean hasMoreElements() {
+          return next();
+        }
+        @Override
+        public URL nextElement() {
+          if (!next()) {
+            throw new NoSuchElementException();
+          }
+          return tmp.get(index).nextElement();
+        }
+        private boolean next() {
+          while (index < tmp.size()) {
+            if (tmp.get(index) != null && tmp.get(index).hasMoreElements()) {
+              return true;
+            }
+            index++;
+          }
+          return false;
+        }
+      };
+    }
+  }
+
   private Class<?> getLowestSubclass(Set<Class<?>> notInterfaces) throws
        UnableToProxyException {
     

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java?rev=1603727&r1=1603726&r2=1603727&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java Thu Jun 19 07:01:32 2014
@@ -271,6 +271,10 @@ public class ProxySubclassAdapter extend
         // read the current class and use a
         // ProxySubclassHierarchyAdapter
         // to process only methods on that class that are in the list
+        ClassLoader loader = currentlyAnalysedClass.getClassLoader();
+        if (loader == null) {
+          loader = this.loader;
+        }
         ClassReader cr = new ClassReader(loader.getResourceAsStream(currentlyAnalysedClass
             .getName().replaceAll("\\.", "/")
             + ".class"));

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java?rev=1603727&r1=1603726&r2=1603727&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java Thu Jun 19 07:01:32 2014
@@ -72,9 +72,13 @@ public class ProxySubclassGenerator
 
   public static Class<?> getProxySubclass(Class<?> aClass) throws UnableToProxyException
   {
+    return getProxySubclass(aClass, aClass.getClassLoader());
+  }
+
+  public static Class<?> getProxySubclass(Class<?> aClass, ClassLoader loader) throws UnableToProxyException
+  {
     LOGGER.debug(Constants.LOG_ENTRY, "getProxySubclass", new Object[] { aClass });
 
-    ClassLoader loader = aClass.getClassLoader();
     // in the special case where the loader is null we use a default classloader
     // this is for subclassing java.* or javax.* packages, so that one will do
     if (loader == null) loader = defaultClassLoader;
@@ -152,13 +156,19 @@ public class ProxySubclassGenerator
   public static Object newProxySubclassInstance(Class<?> classToProxy, InvocationHandler ih)
       throws UnableToProxyException
   {
+    return newProxySubclassInstance(classToProxy, classToProxy.getClassLoader(), ih);
+  }
+
+  public static Object newProxySubclassInstance(Class<?> classToProxy, ClassLoader loader, InvocationHandler ih)
+      throws UnableToProxyException
+  {
 
     LOGGER.debug(Constants.LOG_ENTRY, "newProxySubclassInstance", new Object[] {
-        classToProxy, ih });
+        classToProxy, loader, ih });
 
     Object proxySubclassInstance = null;
     try {
-      Class<?> generatedProxySubclass = getProxySubclass(classToProxy);
+      Class<?> generatedProxySubclass = getProxySubclass(classToProxy, loader);
       LOGGER.debug("Getting the proxy subclass constructor");
       // Because the newer JVMs throw a VerifyError if a class attempts to in a constructor other than their superclasses constructor,
       // and because we can't know what objects/values we need to pass into the class being proxied constructor, 

Modified: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java?rev=1603727&r1=1603726&r2=1603727&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java (original)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java Thu Jun 19 07:01:32 2014
@@ -23,12 +23,18 @@ import static org.junit.Assert.assertFal
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Callable;
 
 import org.apache.aries.proxy.FinalModifierException;
@@ -40,6 +46,7 @@ import org.apache.aries.proxy.impl.Proxy
 import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
 import org.apache.aries.proxy.impl.gen.ProxySubclassGenerator;
 import org.apache.aries.proxy.impl.gen.ProxySubclassMethodHashSet;
+import org.apache.aries.util.io.IOUtils;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -236,6 +243,86 @@ public class ProxySubclassGeneratorTest 
     ((FakeInvocationHandler)ih).setDelegate(GENERIC_CLASS.newInstance());
     super.testGenerics();
   }
+
+  @Test
+  public void testClassLoaders() throws Exception {
+    ClassLoader clA = new LimitedClassLoader("org.apache.aries.proxy.test.a", null, null);
+    ClassLoader clB = new LimitedClassLoader("org.apache.aries.proxy.test.b", "org.apache.aries.proxy.test.a", clA);
+    ClassLoader clC = new LimitedClassLoader("org.apache.aries.proxy.test.c", "org.apache.aries.proxy.test.b", clB);
+
+    Class<?> clazzA = clA.loadClass("org.apache.aries.proxy.test.a.ProxyTestClassA");
+    Class<?> clazzB = clB.loadClass("org.apache.aries.proxy.test.b.ProxyTestClassB");
+    Class<?> clazzC = clC.loadClass("org.apache.aries.proxy.test.c.ProxyTestClassC");
+
+    final Object object = clazzC.getConstructor(String.class).newInstance("hello");
+
+    o = new AsmProxyManager().createNewProxy(null, Arrays.asList(clazzA, clazzB, clazzC), constantly(object), null);
+    generatedProxySubclass = o.getClass();
+    Method m = generatedProxySubclass.getDeclaredMethod("hello", new Class[] {});
+    Object returned = m.invoke(o);
+    assertEquals("hello", returned);
+  }
+
+  private static class LimitedClassLoader extends ClassLoader {
+    Set<String> providedPackages;
+    Set<String> importedPackages;
+    List<ClassLoader> parents;
+
+    public LimitedClassLoader(String provided, String imported, ClassLoader parent) {
+      providedPackages = Collections.singleton(provided);
+      importedPackages = imported != null ? Collections.singleton(imported) : Collections.<String>emptySet();
+      parents = parent != null ? Collections.singletonList(parent) : Collections.<ClassLoader>emptyList();
+    }
+
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+      synchronized (getClassLoadingLock(name)) {
+        // First, check if the class has already been loaded
+        Class<?> c = findLoadedClass(name);
+        if (c == null) {
+          String pkg = name.substring(0, name.lastIndexOf('.'));
+          if (pkg.startsWith("java.") || pkg.startsWith("sun.reflect")) {
+            return getClass().getClassLoader().loadClass(name);
+          } else if (providedPackages.contains(pkg)) {
+            c = findClass(name);
+          } else if (importedPackages.contains(pkg)) {
+            for (ClassLoader cl : parents) {
+              try {
+                c = cl.loadClass(name);
+              } catch (ClassNotFoundException e) {
+                // Ignore
+              }
+            }
+          }
+        }
+        if (c == null) {
+          throw new ClassNotFoundException(name);
+        }
+        if (resolve) {
+          resolveClass(c);
+        }
+        return c;
+      }
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+      String pkg = name.substring(0, name.lastIndexOf('.'));
+      if (getPackage(pkg) == null) {
+        definePackage(pkg, null, null, null, null, null, null, null);
+      }
+      String path = name.replace('.', '/').concat(".class");
+      InputStream is = LimitedClassLoader.class.getClassLoader().getResourceAsStream(path);
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      try {
+        IOUtils.copy(is, baos);
+      } catch (IOException e) {
+        throw new ClassNotFoundException(name, e);
+      }
+      byte[] buf = baos.toByteArray();
+      return defineClass(name, buf, 0, buf.length);
+    }
+  }
   
   private Class<?> getGeneratedSubclass() throws Exception
   {
@@ -317,4 +404,12 @@ public class ProxySubclassGeneratorTest 
   protected Object getP3() {
     return new ProxyTestClassGeneral();
   }
+
+  private Callable<Object> constantly(final Object result) {
+    return new Callable<Object>() {
+      public Object call() throws Exception {
+        return result;
+      }
+    };
+  }
 }

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java?rev=1603727&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java Thu Jun 19 07:01:32 2014
@@ -0,0 +1,32 @@
+/*
+ * 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.aries.proxy.test.a;
+
+public class ProxyTestClassA {
+
+  private final String message;
+
+  public ProxyTestClassA(String message) {
+    this.message = message;
+  }
+
+  public String getMessage() {
+     return message;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java?rev=1603727&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java Thu Jun 19 07:01:32 2014
@@ -0,0 +1,28 @@
+/*
+ * 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.aries.proxy.test.b;
+
+import org.apache.aries.proxy.test.a.ProxyTestClassA;
+
+public class ProxyTestClassB extends ProxyTestClassA {
+
+  public ProxyTestClassB(String message) {
+    super(message);
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java?rev=1603727&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java Thu Jun 19 07:01:32 2014
@@ -0,0 +1,33 @@
+/*
+ * 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.aries.proxy.test.c;
+
+import org.apache.aries.proxy.test.b.ProxyTestClassB;
+
+public class ProxyTestClassC extends ProxyTestClassB {
+
+  public ProxyTestClassC(String message) {
+    super(message);
+  }
+
+  public String hello() {
+    return getMessage();
+  }
+
+}



Re: svn commit: r1603727 - in /aries/trunk/proxy/proxy-impl/src: main/java/org/apache/aries/proxy/impl/ main/java/org/apache/aries/proxy/impl/gen/ test/java/org/apache/aries/blueprint/proxy/ test/java/org/apache/aries/proxy/test/ test/java/org/apache/aries...

Posted by Mark Nuttall <mn...@apache.org>.
Hi Guillaume,
Is it possible that you missed a small change out of this commit?

/org.apache.aries.proxy.impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
line 279 states,
 synchronized (getClassLoadingLock(name)) {

However the getClassLoadingLock() method does not exist. This is preventing
the test class from compiling, and so breaking the build, as per recent
notes from Jenkins.

Many thanks in advance,
Regards,
Mark



On 19 June 2014 08:01, <gn...@apache.org> wrote:

> Author: gnodet
> Date: Thu Jun 19 07:01:32 2014
> New Revision: 1603727
>
> URL: http://svn.apache.org/r1603727
> Log:
> [ARIES-1216] Error when creating proxies with an invisible super class in
> the hierarchy
>
> Added:
>     aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> Modified:
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> Thu Jun 19 07:01:32 2014
> @@ -18,13 +18,19 @@
>   */
>  package org.apache.aries.proxy.impl;
>
> +import java.io.IOException;
>  import java.lang.reflect.Constructor;
>  import java.lang.reflect.InvocationHandler;
>  import java.lang.reflect.Modifier;
>  import java.lang.reflect.Proxy;
> +import java.net.URL;
> +import java.util.ArrayList;
>  import java.util.Collection;
> +import java.util.Enumeration;
>  import java.util.HashSet;
>  import java.util.Iterator;
> +import java.util.List;
> +import java.util.NoSuchElementException;
>  import java.util.Set;
>  import java.util.concurrent.Callable;
>
> @@ -100,13 +106,100 @@ public final class AsmProxyManager exten
>          }
>        }
>        if(proxyObject == null){
> -        proxyObject =
> ProxySubclassGenerator.newProxySubclassInstance(classToProxy, new
> ProxyHandler(this, dispatcher, listener));
> +        // ARIES-1216 : in some cases, some class can not be visible from
> the root class classloader.
> +        // If that's the case, we need to build a custom classloader that
> has visibility on all those classes
> +        // If we could generate a proper constructor this would not be
> necessary, but since we have to rely
> +        // on the generated serialization constructor to bypass the JVM
> verifier, we don't have much choice
> +        ClassLoader classLoader = classToProxy.getClassLoader();
> +        boolean allVisible = true;
> +        for (Class<?> clazz : classes) {
> +          try {
> +            if (classLoader.loadClass(clazz.getName()) != clazz) {
> +              throw new UnableToProxyException(classToProxy, "The
> requested class " + clazz + " is different from the one seen by by " +
> classToProxy);
> +            }
> +          } catch (ClassNotFoundException e) {
> +            allVisible = false;
> +            break;
> +          }
> +        }
> +        if (!allVisible) {
> +          List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
> +          for (Class<?> clazz : classes) {
> +            ClassLoader cl = clazz.getClassLoader();
> +            if (cl != null && !classLoaders.contains(cl)) {
> +              classLoaders.add(cl);
> +            }
> +          }
> +          classLoader = new MultiClassLoader(classLoaders);
> +        }
> +        proxyObject =
> ProxySubclassGenerator.newProxySubclassInstance(classToProxy, classLoader,
> new ProxyHandler(this, dispatcher, listener));
>        }
>      }
>
>      return proxyObject;
>    }
>
> +  private static class MultiClassLoader extends ClassLoader {
> +    private final List<ClassLoader> parents;
> +    private MultiClassLoader(List<ClassLoader> parents) {
> +      this.parents = parents;
> +    }
> +
> +    @Override
> +    public Class<?> loadClass(String name, boolean resolve) throws
> ClassNotFoundException {
> +      for (ClassLoader cl : parents) {
> +         try {
> +           return cl.loadClass(name);
> +         } catch (ClassNotFoundException e) {
> +           // Ignore
> +         }
> +        }
> +        throw new ClassNotFoundException(name);
> +    }
> +
> +    @Override
> +    public URL getResource(String name) {
> +      for (ClassLoader cl : parents) {
> +         URL url = cl.getResource(name);
> +         if (url != null) {
> +           return url;
> +         }
> +       }
> +       return null;
> +    }
> +
> +    @Override
> +    public Enumeration<URL> getResources(String name) throws IOException {
> +      final List<Enumeration<URL>> tmp = new
> ArrayList<Enumeration<URL>>();
> +      for (ClassLoader cl : parents) {
> +        tmp.add(cl.getResources(name));
> +      }
> +      return new Enumeration<URL>() {
> +        int index = 0;
> +        @Override
> +        public boolean hasMoreElements() {
> +          return next();
> +        }
> +        @Override
> +        public URL nextElement() {
> +          if (!next()) {
> +            throw new NoSuchElementException();
> +          }
> +          return tmp.get(index).nextElement();
> +        }
> +        private boolean next() {
> +          while (index < tmp.size()) {
> +            if (tmp.get(index) != null &&
> tmp.get(index).hasMoreElements()) {
> +              return true;
> +            }
> +            index++;
> +          }
> +          return false;
> +        }
> +      };
> +    }
> +  }
> +
>    private Class<?> getLowestSubclass(Set<Class<?>> notInterfaces) throws
>         UnableToProxyException {
>
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> Thu Jun 19 07:01:32 2014
> @@ -271,6 +271,10 @@ public class ProxySubclassAdapter extend
>          // read the current class and use a
>          // ProxySubclassHierarchyAdapter
>          // to process only methods on that class that are in the list
> +        ClassLoader loader = currentlyAnalysedClass.getClassLoader();
> +        if (loader == null) {
> +          loader = this.loader;
> +        }
>          ClassReader cr = new
> ClassReader(loader.getResourceAsStream(currentlyAnalysedClass
>              .getName().replaceAll("\\.", "/")
>              + ".class"));
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> Thu Jun 19 07:01:32 2014
> @@ -72,9 +72,13 @@ public class ProxySubclassGenerator
>
>    public static Class<?> getProxySubclass(Class<?> aClass) throws
> UnableToProxyException
>    {
> +    return getProxySubclass(aClass, aClass.getClassLoader());
> +  }
> +
> +  public static Class<?> getProxySubclass(Class<?> aClass, ClassLoader
> loader) throws UnableToProxyException
> +  {
>      LOGGER.debug(Constants.LOG_ENTRY, "getProxySubclass", new Object[] {
> aClass });
>
> -    ClassLoader loader = aClass.getClassLoader();
>      // in the special case where the loader is null we use a default
> classloader
>      // this is for subclassing java.* or javax.* packages, so that one
> will do
>      if (loader == null) loader = defaultClassLoader;
> @@ -152,13 +156,19 @@ public class ProxySubclassGenerator
>    public static Object newProxySubclassInstance(Class<?> classToProxy,
> InvocationHandler ih)
>        throws UnableToProxyException
>    {
> +    return newProxySubclassInstance(classToProxy,
> classToProxy.getClassLoader(), ih);
> +  }
> +
> +  public static Object newProxySubclassInstance(Class<?> classToProxy,
> ClassLoader loader, InvocationHandler ih)
> +      throws UnableToProxyException
> +  {
>
>      LOGGER.debug(Constants.LOG_ENTRY, "newProxySubclassInstance", new
> Object[] {
> -        classToProxy, ih });
> +        classToProxy, loader, ih });
>
>      Object proxySubclassInstance = null;
>      try {
> -      Class<?> generatedProxySubclass = getProxySubclass(classToProxy);
> +      Class<?> generatedProxySubclass = getProxySubclass(classToProxy,
> loader);
>        LOGGER.debug("Getting the proxy subclass constructor");
>        // Because the newer JVMs throw a VerifyError if a class attempts
> to in a constructor other than their superclasses constructor,
>        // and because we can't know what objects/values we need to pass
> into the class being proxied constructor,
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> Thu Jun 19 07:01:32 2014
> @@ -23,12 +23,18 @@ import static org.junit.Assert.assertFal
>  import static org.junit.Assert.assertNotNull;
>  import static org.junit.Assert.assertTrue;
>
> +import java.io.ByteArrayOutputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
>  import java.lang.reflect.InvocationHandler;
>  import java.lang.reflect.InvocationTargetException;
>  import java.lang.reflect.Method;
>  import java.lang.reflect.Modifier;
>  import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.Collections;
>  import java.util.List;
> +import java.util.Set;
>  import java.util.concurrent.Callable;
>
>  import org.apache.aries.proxy.FinalModifierException;
> @@ -40,6 +46,7 @@ import org.apache.aries.proxy.impl.Proxy
>  import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
>  import org.apache.aries.proxy.impl.gen.ProxySubclassGenerator;
>  import org.apache.aries.proxy.impl.gen.ProxySubclassMethodHashSet;
> +import org.apache.aries.util.io.IOUtils;
>  import org.junit.Before;
>  import org.junit.Test;
>
> @@ -236,6 +243,86 @@ public class ProxySubclassGeneratorTest
>      ((FakeInvocationHandler)ih).setDelegate(GENERIC_CLASS.newInstance());
>      super.testGenerics();
>    }
> +
> +  @Test
> +  public void testClassLoaders() throws Exception {
> +    ClassLoader clA = new
> LimitedClassLoader("org.apache.aries.proxy.test.a", null, null);
> +    ClassLoader clB = new
> LimitedClassLoader("org.apache.aries.proxy.test.b",
> "org.apache.aries.proxy.test.a", clA);
> +    ClassLoader clC = new
> LimitedClassLoader("org.apache.aries.proxy.test.c",
> "org.apache.aries.proxy.test.b", clB);
> +
> +    Class<?> clazzA =
> clA.loadClass("org.apache.aries.proxy.test.a.ProxyTestClassA");
> +    Class<?> clazzB =
> clB.loadClass("org.apache.aries.proxy.test.b.ProxyTestClassB");
> +    Class<?> clazzC =
> clC.loadClass("org.apache.aries.proxy.test.c.ProxyTestClassC");
> +
> +    final Object object =
> clazzC.getConstructor(String.class).newInstance("hello");
> +
> +    o = new AsmProxyManager().createNewProxy(null, Arrays.asList(clazzA,
> clazzB, clazzC), constantly(object), null);
> +    generatedProxySubclass = o.getClass();
> +    Method m = generatedProxySubclass.getDeclaredMethod("hello", new
> Class[] {});
> +    Object returned = m.invoke(o);
> +    assertEquals("hello", returned);
> +  }
> +
> +  private static class LimitedClassLoader extends ClassLoader {
> +    Set<String> providedPackages;
> +    Set<String> importedPackages;
> +    List<ClassLoader> parents;
> +
> +    public LimitedClassLoader(String provided, String imported,
> ClassLoader parent) {
> +      providedPackages = Collections.singleton(provided);
> +      importedPackages = imported != null ?
> Collections.singleton(imported) : Collections.<String>emptySet();
> +      parents = parent != null ? Collections.singletonList(parent) :
> Collections.<ClassLoader>emptyList();
> +    }
> +
> +    @Override
> +    protected Class<?> loadClass(String name, boolean resolve) throws
> ClassNotFoundException {
> +      synchronized (getClassLoadingLock(name)) {
> +        // First, check if the class has already been loaded
> +        Class<?> c = findLoadedClass(name);
> +        if (c == null) {
> +          String pkg = name.substring(0, name.lastIndexOf('.'));
> +          if (pkg.startsWith("java.") || pkg.startsWith("sun.reflect")) {
> +            return getClass().getClassLoader().loadClass(name);
> +          } else if (providedPackages.contains(pkg)) {
> +            c = findClass(name);
> +          } else if (importedPackages.contains(pkg)) {
> +            for (ClassLoader cl : parents) {
> +              try {
> +                c = cl.loadClass(name);
> +              } catch (ClassNotFoundException e) {
> +                // Ignore
> +              }
> +            }
> +          }
> +        }
> +        if (c == null) {
> +          throw new ClassNotFoundException(name);
> +        }
> +        if (resolve) {
> +          resolveClass(c);
> +        }
> +        return c;
> +      }
> +    }
> +
> +    @Override
> +    protected Class<?> findClass(String name) throws
> ClassNotFoundException {
> +      String pkg = name.substring(0, name.lastIndexOf('.'));
> +      if (getPackage(pkg) == null) {
> +        definePackage(pkg, null, null, null, null, null, null, null);
> +      }
> +      String path = name.replace('.', '/').concat(".class");
> +      InputStream is =
> LimitedClassLoader.class.getClassLoader().getResourceAsStream(path);
> +      ByteArrayOutputStream baos = new ByteArrayOutputStream();
> +      try {
> +        IOUtils.copy(is, baos);
> +      } catch (IOException e) {
> +        throw new ClassNotFoundException(name, e);
> +      }
> +      byte[] buf = baos.toByteArray();
> +      return defineClass(name, buf, 0, buf.length);
> +    }
> +  }
>
>    private Class<?> getGeneratedSubclass() throws Exception
>    {
> @@ -317,4 +404,12 @@ public class ProxySubclassGeneratorTest
>    protected Object getP3() {
>      return new ProxyTestClassGeneral();
>    }
> +
> +  private Callable<Object> constantly(final Object result) {
> +    return new Callable<Object>() {
> +      public Object call() throws Exception {
> +        return result;
> +      }
> +    };
> +  }
>  }
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,32 @@
> +/*
> + * 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.aries.proxy.test.a;
> +
> +public class ProxyTestClassA {
> +
> +  private final String message;
> +
> +  public ProxyTestClassA(String message) {
> +    this.message = message;
> +  }
> +
> +  public String getMessage() {
> +     return message;
> +  }
> +}
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,28 @@
> +/*
> + * 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.aries.proxy.test.b;
> +
> +import org.apache.aries.proxy.test.a.ProxyTestClassA;
> +
> +public class ProxyTestClassB extends ProxyTestClassA {
> +
> +  public ProxyTestClassB(String message) {
> +    super(message);
> +  }
> +}
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,33 @@
> +/*
> + * 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.aries.proxy.test.c;
> +
> +import org.apache.aries.proxy.test.b.ProxyTestClassB;
> +
> +public class ProxyTestClassC extends ProxyTestClassB {
> +
> +  public ProxyTestClassC(String message) {
> +    super(message);
> +  }
> +
> +  public String hello() {
> +    return getMessage();
> +  }
> +
> +}
>
>
>

Re: svn commit: r1603727 - in /aries/trunk/proxy/proxy-impl/src: main/java/org/apache/aries/proxy/impl/ main/java/org/apache/aries/proxy/impl/gen/ test/java/org/apache/aries/blueprint/proxy/ test/java/org/apache/aries/proxy/test/ test/java/org/apache/aries...

Posted by Mark Nuttall <mn...@apache.org>.
Hi Guillaume,
Is it possible that you missed a small change out of this commit?

/org.apache.aries.proxy.impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
line 279 states,
 synchronized (getClassLoadingLock(name)) {

However the getClassLoadingLock() method does not exist. This is preventing
the test class from compiling, and so breaking the build, as per recent
notes from Jenkins.

Many thanks in advance,
Regards,
Mark



On 19 June 2014 08:01, <gn...@apache.org> wrote:

> Author: gnodet
> Date: Thu Jun 19 07:01:32 2014
> New Revision: 1603727
>
> URL: http://svn.apache.org/r1603727
> Log:
> [ARIES-1216] Error when creating proxies with an invisible super class in
> the hierarchy
>
> Added:
>     aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> Modified:
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
>
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
>
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/AsmProxyManager.java
> Thu Jun 19 07:01:32 2014
> @@ -18,13 +18,19 @@
>   */
>  package org.apache.aries.proxy.impl;
>
> +import java.io.IOException;
>  import java.lang.reflect.Constructor;
>  import java.lang.reflect.InvocationHandler;
>  import java.lang.reflect.Modifier;
>  import java.lang.reflect.Proxy;
> +import java.net.URL;
> +import java.util.ArrayList;
>  import java.util.Collection;
> +import java.util.Enumeration;
>  import java.util.HashSet;
>  import java.util.Iterator;
> +import java.util.List;
> +import java.util.NoSuchElementException;
>  import java.util.Set;
>  import java.util.concurrent.Callable;
>
> @@ -100,13 +106,100 @@ public final class AsmProxyManager exten
>          }
>        }
>        if(proxyObject == null){
> -        proxyObject =
> ProxySubclassGenerator.newProxySubclassInstance(classToProxy, new
> ProxyHandler(this, dispatcher, listener));
> +        // ARIES-1216 : in some cases, some class can not be visible from
> the root class classloader.
> +        // If that's the case, we need to build a custom classloader that
> has visibility on all those classes
> +        // If we could generate a proper constructor this would not be
> necessary, but since we have to rely
> +        // on the generated serialization constructor to bypass the JVM
> verifier, we don't have much choice
> +        ClassLoader classLoader = classToProxy.getClassLoader();
> +        boolean allVisible = true;
> +        for (Class<?> clazz : classes) {
> +          try {
> +            if (classLoader.loadClass(clazz.getName()) != clazz) {
> +              throw new UnableToProxyException(classToProxy, "The
> requested class " + clazz + " is different from the one seen by by " +
> classToProxy);
> +            }
> +          } catch (ClassNotFoundException e) {
> +            allVisible = false;
> +            break;
> +          }
> +        }
> +        if (!allVisible) {
> +          List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
> +          for (Class<?> clazz : classes) {
> +            ClassLoader cl = clazz.getClassLoader();
> +            if (cl != null && !classLoaders.contains(cl)) {
> +              classLoaders.add(cl);
> +            }
> +          }
> +          classLoader = new MultiClassLoader(classLoaders);
> +        }
> +        proxyObject =
> ProxySubclassGenerator.newProxySubclassInstance(classToProxy, classLoader,
> new ProxyHandler(this, dispatcher, listener));
>        }
>      }
>
>      return proxyObject;
>    }
>
> +  private static class MultiClassLoader extends ClassLoader {
> +    private final List<ClassLoader> parents;
> +    private MultiClassLoader(List<ClassLoader> parents) {
> +      this.parents = parents;
> +    }
> +
> +    @Override
> +    public Class<?> loadClass(String name, boolean resolve) throws
> ClassNotFoundException {
> +      for (ClassLoader cl : parents) {
> +         try {
> +           return cl.loadClass(name);
> +         } catch (ClassNotFoundException e) {
> +           // Ignore
> +         }
> +        }
> +        throw new ClassNotFoundException(name);
> +    }
> +
> +    @Override
> +    public URL getResource(String name) {
> +      for (ClassLoader cl : parents) {
> +         URL url = cl.getResource(name);
> +         if (url != null) {
> +           return url;
> +         }
> +       }
> +       return null;
> +    }
> +
> +    @Override
> +    public Enumeration<URL> getResources(String name) throws IOException {
> +      final List<Enumeration<URL>> tmp = new
> ArrayList<Enumeration<URL>>();
> +      for (ClassLoader cl : parents) {
> +        tmp.add(cl.getResources(name));
> +      }
> +      return new Enumeration<URL>() {
> +        int index = 0;
> +        @Override
> +        public boolean hasMoreElements() {
> +          return next();
> +        }
> +        @Override
> +        public URL nextElement() {
> +          if (!next()) {
> +            throw new NoSuchElementException();
> +          }
> +          return tmp.get(index).nextElement();
> +        }
> +        private boolean next() {
> +          while (index < tmp.size()) {
> +            if (tmp.get(index) != null &&
> tmp.get(index).hasMoreElements()) {
> +              return true;
> +            }
> +            index++;
> +          }
> +          return false;
> +        }
> +      };
> +    }
> +  }
> +
>    private Class<?> getLowestSubclass(Set<Class<?>> notInterfaces) throws
>         UnableToProxyException {
>
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java
> Thu Jun 19 07:01:32 2014
> @@ -271,6 +271,10 @@ public class ProxySubclassAdapter extend
>          // read the current class and use a
>          // ProxySubclassHierarchyAdapter
>          // to process only methods on that class that are in the list
> +        ClassLoader loader = currentlyAnalysedClass.getClassLoader();
> +        if (loader == null) {
> +          loader = this.loader;
> +        }
>          ClassReader cr = new
> ClassReader(loader.getResourceAsStream(currentlyAnalysedClass
>              .getName().replaceAll("\\.", "/")
>              + ".class"));
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassGenerator.java
> Thu Jun 19 07:01:32 2014
> @@ -72,9 +72,13 @@ public class ProxySubclassGenerator
>
>    public static Class<?> getProxySubclass(Class<?> aClass) throws
> UnableToProxyException
>    {
> +    return getProxySubclass(aClass, aClass.getClassLoader());
> +  }
> +
> +  public static Class<?> getProxySubclass(Class<?> aClass, ClassLoader
> loader) throws UnableToProxyException
> +  {
>      LOGGER.debug(Constants.LOG_ENTRY, "getProxySubclass", new Object[] {
> aClass });
>
> -    ClassLoader loader = aClass.getClassLoader();
>      // in the special case where the loader is null we use a default
> classloader
>      // this is for subclassing java.* or javax.* packages, so that one
> will do
>      if (loader == null) loader = defaultClassLoader;
> @@ -152,13 +156,19 @@ public class ProxySubclassGenerator
>    public static Object newProxySubclassInstance(Class<?> classToProxy,
> InvocationHandler ih)
>        throws UnableToProxyException
>    {
> +    return newProxySubclassInstance(classToProxy,
> classToProxy.getClassLoader(), ih);
> +  }
> +
> +  public static Object newProxySubclassInstance(Class<?> classToProxy,
> ClassLoader loader, InvocationHandler ih)
> +      throws UnableToProxyException
> +  {
>
>      LOGGER.debug(Constants.LOG_ENTRY, "newProxySubclassInstance", new
> Object[] {
> -        classToProxy, ih });
> +        classToProxy, loader, ih });
>
>      Object proxySubclassInstance = null;
>      try {
> -      Class<?> generatedProxySubclass = getProxySubclass(classToProxy);
> +      Class<?> generatedProxySubclass = getProxySubclass(classToProxy,
> loader);
>        LOGGER.debug("Getting the proxy subclass constructor");
>        // Because the newer JVMs throw a VerifyError if a class attempts
> to in a constructor other than their superclasses constructor,
>        // and because we can't know what objects/values we need to pass
> into the class being proxied constructor,
>
> Modified:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java?rev=1603727&r1=1603726&r2=1603727&view=diff
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> (original)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
> Thu Jun 19 07:01:32 2014
> @@ -23,12 +23,18 @@ import static org.junit.Assert.assertFal
>  import static org.junit.Assert.assertNotNull;
>  import static org.junit.Assert.assertTrue;
>
> +import java.io.ByteArrayOutputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
>  import java.lang.reflect.InvocationHandler;
>  import java.lang.reflect.InvocationTargetException;
>  import java.lang.reflect.Method;
>  import java.lang.reflect.Modifier;
>  import java.util.ArrayList;
> +import java.util.Arrays;
> +import java.util.Collections;
>  import java.util.List;
> +import java.util.Set;
>  import java.util.concurrent.Callable;
>
>  import org.apache.aries.proxy.FinalModifierException;
> @@ -40,6 +46,7 @@ import org.apache.aries.proxy.impl.Proxy
>  import org.apache.aries.proxy.impl.SingleInstanceDispatcher;
>  import org.apache.aries.proxy.impl.gen.ProxySubclassGenerator;
>  import org.apache.aries.proxy.impl.gen.ProxySubclassMethodHashSet;
> +import org.apache.aries.util.io.IOUtils;
>  import org.junit.Before;
>  import org.junit.Test;
>
> @@ -236,6 +243,86 @@ public class ProxySubclassGeneratorTest
>      ((FakeInvocationHandler)ih).setDelegate(GENERIC_CLASS.newInstance());
>      super.testGenerics();
>    }
> +
> +  @Test
> +  public void testClassLoaders() throws Exception {
> +    ClassLoader clA = new
> LimitedClassLoader("org.apache.aries.proxy.test.a", null, null);
> +    ClassLoader clB = new
> LimitedClassLoader("org.apache.aries.proxy.test.b",
> "org.apache.aries.proxy.test.a", clA);
> +    ClassLoader clC = new
> LimitedClassLoader("org.apache.aries.proxy.test.c",
> "org.apache.aries.proxy.test.b", clB);
> +
> +    Class<?> clazzA =
> clA.loadClass("org.apache.aries.proxy.test.a.ProxyTestClassA");
> +    Class<?> clazzB =
> clB.loadClass("org.apache.aries.proxy.test.b.ProxyTestClassB");
> +    Class<?> clazzC =
> clC.loadClass("org.apache.aries.proxy.test.c.ProxyTestClassC");
> +
> +    final Object object =
> clazzC.getConstructor(String.class).newInstance("hello");
> +
> +    o = new AsmProxyManager().createNewProxy(null, Arrays.asList(clazzA,
> clazzB, clazzC), constantly(object), null);
> +    generatedProxySubclass = o.getClass();
> +    Method m = generatedProxySubclass.getDeclaredMethod("hello", new
> Class[] {});
> +    Object returned = m.invoke(o);
> +    assertEquals("hello", returned);
> +  }
> +
> +  private static class LimitedClassLoader extends ClassLoader {
> +    Set<String> providedPackages;
> +    Set<String> importedPackages;
> +    List<ClassLoader> parents;
> +
> +    public LimitedClassLoader(String provided, String imported,
> ClassLoader parent) {
> +      providedPackages = Collections.singleton(provided);
> +      importedPackages = imported != null ?
> Collections.singleton(imported) : Collections.<String>emptySet();
> +      parents = parent != null ? Collections.singletonList(parent) :
> Collections.<ClassLoader>emptyList();
> +    }
> +
> +    @Override
> +    protected Class<?> loadClass(String name, boolean resolve) throws
> ClassNotFoundException {
> +      synchronized (getClassLoadingLock(name)) {
> +        // First, check if the class has already been loaded
> +        Class<?> c = findLoadedClass(name);
> +        if (c == null) {
> +          String pkg = name.substring(0, name.lastIndexOf('.'));
> +          if (pkg.startsWith("java.") || pkg.startsWith("sun.reflect")) {
> +            return getClass().getClassLoader().loadClass(name);
> +          } else if (providedPackages.contains(pkg)) {
> +            c = findClass(name);
> +          } else if (importedPackages.contains(pkg)) {
> +            for (ClassLoader cl : parents) {
> +              try {
> +                c = cl.loadClass(name);
> +              } catch (ClassNotFoundException e) {
> +                // Ignore
> +              }
> +            }
> +          }
> +        }
> +        if (c == null) {
> +          throw new ClassNotFoundException(name);
> +        }
> +        if (resolve) {
> +          resolveClass(c);
> +        }
> +        return c;
> +      }
> +    }
> +
> +    @Override
> +    protected Class<?> findClass(String name) throws
> ClassNotFoundException {
> +      String pkg = name.substring(0, name.lastIndexOf('.'));
> +      if (getPackage(pkg) == null) {
> +        definePackage(pkg, null, null, null, null, null, null, null);
> +      }
> +      String path = name.replace('.', '/').concat(".class");
> +      InputStream is =
> LimitedClassLoader.class.getClassLoader().getResourceAsStream(path);
> +      ByteArrayOutputStream baos = new ByteArrayOutputStream();
> +      try {
> +        IOUtils.copy(is, baos);
> +      } catch (IOException e) {
> +        throw new ClassNotFoundException(name, e);
> +      }
> +      byte[] buf = baos.toByteArray();
> +      return defineClass(name, buf, 0, buf.length);
> +    }
> +  }
>
>    private Class<?> getGeneratedSubclass() throws Exception
>    {
> @@ -317,4 +404,12 @@ public class ProxySubclassGeneratorTest
>    protected Object getP3() {
>      return new ProxyTestClassGeneral();
>    }
> +
> +  private Callable<Object> constantly(final Object result) {
> +    return new Callable<Object>() {
> +      public Object call() throws Exception {
> +        return result;
> +      }
> +    };
> +  }
>  }
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/a/ProxyTestClassA.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,32 @@
> +/*
> + * 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.aries.proxy.test.a;
> +
> +public class ProxyTestClassA {
> +
> +  private final String message;
> +
> +  public ProxyTestClassA(String message) {
> +    this.message = message;
> +  }
> +
> +  public String getMessage() {
> +     return message;
> +  }
> +}
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/b/ProxyTestClassB.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,28 @@
> +/*
> + * 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.aries.proxy.test.b;
> +
> +import org.apache.aries.proxy.test.a.ProxyTestClassA;
> +
> +public class ProxyTestClassB extends ProxyTestClassA {
> +
> +  public ProxyTestClassB(String message) {
> +    super(message);
> +  }
> +}
>
> Added:
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java?rev=1603727&view=auto
>
> ==============================================================================
> ---
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> (added)
> +++
> aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/proxy/test/c/ProxyTestClassC.java
> Thu Jun 19 07:01:32 2014
> @@ -0,0 +1,33 @@
> +/*
> + * 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.aries.proxy.test.c;
> +
> +import org.apache.aries.proxy.test.b.ProxyTestClassB;
> +
> +public class ProxyTestClassC extends ProxyTestClassB {
> +
> +  public ProxyTestClassC(String message) {
> +    super(message);
> +  }
> +
> +  public String hello() {
> +    return getMessage();
> +  }
> +
> +}
>
>
>