You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2011/11/04 20:12:30 UTC

svn commit: r1197720 - in /aries/trunk/proxy/proxy-impl/src: main/java/org/apache/aries/proxy/impl/common/ test/java/org/apache/aries/blueprint/proxy/

Author: timothyjward
Date: Fri Nov  4 19:12:30 2011
New Revision: 1197720

URL: http://svn.apache.org/viewvc?rev=1197720&view=rev
Log:
ARIES-775: Fix ClassCircularityError seen on Mac VMs when locating no-args constructors.

Added:
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/ConstructorFinder.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChild.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChildParent.java
Modified:
    aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/AbstractWovenProxyAdapter.java
    aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java

Modified: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/AbstractWovenProxyAdapter.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/AbstractWovenProxyAdapter.java?rev=1197720&r1=1197719&r2=1197720&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/AbstractWovenProxyAdapter.java (original)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/AbstractWovenProxyAdapter.java Fri Nov  4 19:12:30 2011
@@ -19,6 +19,7 @@
 package org.apache.aries.proxy.impl.common;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
 import java.math.BigDecimal;
@@ -241,13 +242,9 @@ public abstract class AbstractWovenProxy
             nonObjectSupers.add(nextSuper);
             nextSuper = nextSuper.getSuperclass();
           }
-          try {
-            superHasNoArgsConstructor = (superClass.getDeclaredConstructor().
-                     getModifiers() & Modifier.PRIVATE) == 0;
-          } catch (NoSuchMethodException nsme) {
-            // This is a no-op here, but means we need to add a no-Args that
-            // delegates to Object#<init>() yuck :(
-          }
+          //Don't use reflection - it can be dangerous
+          superHasNoArgsConstructor = superHasNoArgsConstructor(superName, name);
+
         } else {
           superHasNoArgsConstructor = true;
         }
@@ -274,6 +271,31 @@ public abstract class AbstractWovenProxy
     }
   }
 
+  /**
+   * This method allows us to determine whether a superclass has a
+   * non-private no-args constructor without causing it to initialize.
+   * This avoids a potential ClassCircularityError on Mac VMs if the
+   * initialization references the subclass being woven. Odd, but seen
+   * in the wild!
+   */
+  private final boolean superHasNoArgsConstructor(String superName, String name) {
+    
+    ConstructorFinder cf = new ConstructorFinder();
+    
+    try {
+      InputStream is = loader.getResourceAsStream(superName +".class");
+    
+      if(is == null)
+        throw new IOException();
+      
+      new ClassReader(is).accept(cf, ClassReader.SKIP_FRAMES + ClassReader.SKIP_DEBUG + ClassReader.SKIP_CODE);
+    } catch (IOException ioe) {
+      UnableToProxyException u = new UnableToProxyException(name, ioe);
+      throw new RuntimeException(NLS.MESSAGES.getMessage("cannot.load.superclass", superName.replace('/', '.'), typeBeingWoven.getClassName()), u);
+    }
+    return cf.hasNoArgsConstructor();
+  }
+  
   private boolean checkInterfacesForSerializability(String[] interfaces) throws ClassNotFoundException {
     for(String iface : interfaces)
     {

Added: aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/ConstructorFinder.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/ConstructorFinder.java?rev=1197720&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/ConstructorFinder.java (added)
+++ aries/trunk/proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/common/ConstructorFinder.java Fri Nov  4 19:12:30 2011
@@ -0,0 +1,53 @@
+/*
+ * 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.impl.common;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+
+public class ConstructorFinder extends ClassAdapter
+{
+
+  private boolean hasNoArgsConstructor = false;
+  
+  public boolean hasNoArgsConstructor()
+  {
+    return hasNoArgsConstructor;
+  }
+
+  public ConstructorFinder()
+  {
+    super(new EmptyVisitor());
+  }
+
+  @Override
+  public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+      String[] exceptions)
+  {
+    if("<init>".equals(name)) {
+      if(Type.getArgumentTypes(desc).length == 0 && (access & ACC_PRIVATE) == 0)
+        hasNoArgsConstructor = true;
+    }
+    return null;
+  }
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChild.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChild.java?rev=1197720&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChild.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChild.java Fri Nov  4 19:12:30 2011
@@ -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.blueprint.proxy;
+
+public class ProxyTestClassStaticInitOfChild extends ProxyTestClassStaticInitOfChildParent
+{
+  
+  public ProxyTestClassStaticInitOfChild(){
+    super("test");
+  }
+  
+}

Added: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChildParent.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChildParent.java?rev=1197720&view=auto
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChildParent.java (added)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassStaticInitOfChildParent.java Fri Nov  4 19:12:30 2011
@@ -0,0 +1,34 @@
+/*
+ * 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.blueprint.proxy;
+
+public class ProxyTestClassStaticInitOfChildParent
+{
+
+  private static final ProxyTestClassStaticInitOfChildParent child = new ProxyTestClassStaticInitOfChild();
+  
+  public static void doStuff() {
+    //Do silly stuff;
+    child.toString();
+  }
+  
+  public ProxyTestClassStaticInitOfChildParent(String s){
+    
+  }
+}

Modified: aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java?rev=1197720&r1=1197719&r2=1197720&view=diff
==============================================================================
--- aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java (original)
+++ aries/trunk/proxy/proxy-impl/src/test/java/org/apache/aries/blueprint/proxy/WovenProxyGeneratorTest.java Fri Nov  4 19:12:30 2011
@@ -30,6 +30,7 @@ import java.io.ObjectOutputStream;
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -70,7 +71,7 @@ public class WovenProxyGeneratorTest ext
   }
   
   /** An array of classes that will be woven - note no UnweavableParents should be in here! */
-  private static final Class<?>[] CLASSES = new Class<?>[]{TEST_CLASS, ProxyTestClassSuper.class,
+  private static final List<Class<?>> CLASSES = Arrays.asList(new Class<?>[]{TEST_CLASS, ProxyTestClassSuper.class,
     ProxyTestClassFinalMethod.class, ProxyTestClassFinal.class, ProxyTestClassGeneric.class,
     ProxyTestClassGenericSuper.class, ProxyTestClassCovariant.class, ProxyTestClassCovariantOverride.class,
     ProxyTestClassUnweavableChild.class, ProxyTestClassUnweavableSibling.class, ProxyTestClassInner.class, 
@@ -78,7 +79,11 @@ public class WovenProxyGeneratorTest ext
     ProxyTestClassUnweavableChildWithFinalMethodParent.class, 
     ProxyTestClassUnweavableChildWithDefaultMethodWrongPackageParent.class, 
     ProxyTestClassSerializable.class, ProxyTestClassSerializableWithSVUID.class,
-    ProxyTestClassSerializableChild.class, ProxyTestClassSerializableInterface.class};
+    ProxyTestClassSerializableChild.class, ProxyTestClassSerializableInterface.class,
+    ProxyTestClassStaticInitOfChild.class});
+  
+  /** An array of classes that are loaded by the WeavingLoader, but not actually woven **/
+  private static final List<Class<?>> OTHER_CLASSES = Arrays.asList(new Class<?>[] {ProxyTestClassStaticInitOfChildParent.class});
  
   private static final Map<String, byte[]> rawClasses = new HashMap<String, byte[]>();
   
@@ -101,7 +106,16 @@ public class WovenProxyGeneratorTest ext
       if(bytes == null)
         return super.loadClass(className, b);
       
-      bytes = WovenProxyGenerator.getWovenProxy(bytes, className, this);
+      boolean weave = false;
+      
+      for(Class<?> c : CLASSES) {
+        if(c.getName().equals(className)) {
+          weave = true;
+          break;
+        }
+      }
+      if(weave)
+        bytes = WovenProxyGenerator.getWovenProxy(bytes, className, this);
       
       return defineClass(className, bytes, 0, bytes.length);
     }
@@ -117,7 +131,12 @@ public class WovenProxyGeneratorTest ext
   @BeforeClass
   public static void setUp() throws Exception
   {
-    for(Class<?> clazz : CLASSES) {
+    List<Class<?>> classes = new ArrayList(CLASSES.size() + OTHER_CLASSES.size());
+    
+    classes.addAll(CLASSES);
+    classes.addAll(OTHER_CLASSES);
+    
+    for(Class<?> clazz : classes) {
       InputStream is = clazz.getClassLoader().getResourceAsStream(
           clazz.getName().replace('.', '/') + ".class");
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -383,6 +402,19 @@ public class WovenProxyGeneratorTest ext
     assertFalse(woven.getDeclaredField("serialVersionUID").isSynthetic());
   }
   
+  /**
+   * This test covers a weird case on Mac VMs where we sometimes
+   * get a ClassCircularityError if a static initializer in a
+   * non-woven superclass references a subclass that's being
+   * woven, and gets triggered by the weaving process. Not known
+   * to fail on IBM or Sun/Oracle VMs
+   */
+  @Test
+  public void testSuperStaticInitOfChild() throws Exception {
+    Class<?> parent = weavingLoader.loadClass(ProxyTestClassStaticInitOfChildParent.class.getName());
+    parent.getMethod("doStuff").invoke(null);
+  }
+  
   @Override
   protected Object getProxyInstance(Class<?> proxyClass) {
     try {