You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/11/02 00:10:14 UTC

svn commit: r1196363 - in /tapestry/tapestry5/trunk: tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ tapestry-ioc/src...

Author: hlship
Date: Tue Nov  1 23:10:13 2011
New Revision: 1196363

URL: http://svn.apache.org/viewvc?rev=1196363&view=rev
Log:
TAP5-1739: Remove use of Javassist for testing reloadable service implementations

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NoopClassLoaderDelegate.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java?rev=1196363&r1=1196362&r2=1196363&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java Tue Nov  1 23:10:13 2011
@@ -178,41 +178,6 @@ public class PropertyConduitSourceImplTe
         assertEquals(inner.getFirstName(), "Howard");
     }
 
-    /**
-     * Or call this the "Hibernate" case; Hibernate creates sub-classes of
-     * entity classes in its own class loader to do
-     * all sorts of proxying. This trips up Javassist.
-     */
-    @Test
-    public void handle_beans_from_unexpected_classloader() throws Exception
-    {
-        throw new Exception("test not yet re-implemented");
-
-        /*
-        // First, create something that looks like a Hibernate proxy.
-
-        ClassFactory factory = new ClassFactoryImpl();
-
-        Class clazz = SimpleBean.class;
-
-        ClassFab cf = factory.newClass(clazz.getName() + "$$Proxy", clazz);
-
-        cf.addInterface(Serializable.class);
-
-        Class proxyClass = cf.createClass();
-
-        SimpleBean simple = (SimpleBean) proxyClass.newInstance();
-
-        assertTrue(simple instanceof Serializable);
-
-        simple.setFirstName("Howard");
-
-        PropertyConduit conduit = source.create(proxyClass, "firstName");
-
-        assertEquals(conduit.get(simple), "Howard");
-        */
-    }
-
     @Test
     public void generics()
     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java?rev=1196363&r1=1196362&r2=1196363&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java Tue Nov  1 23:10:13 2011
@@ -43,30 +43,6 @@ public final class ClassFabUtils
     }
 
     /**
-     * Given a Class instance, convert the name into a path that can be used to locate
-     * the underlying class file on the classpath.
-     *
-     * @since 5.2.0
-     */
-    public static String getPathForClass(Class clazz)
-    {
-        assert clazz != null;
-
-        return getPathForClassNamed(clazz.getName());
-    }
-
-    /**
-     * Given a fully qualified class name, converts to a path on the classpath.
-     *
-     * @since 5.2.0
-     */
-    public static String getPathForClassNamed(String className)
-    {
-        return className.replace('.', '/') + ".class";
-    }
-
-
-    /**
      * Converts a URL with protocol "file" to a File instance.
      *
      * @since 5.2.0

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java?rev=1196363&r1=1196362&r2=1196363&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java Tue Nov  1 23:10:13 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2011 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,30 +14,23 @@
 
 package org.apache.tapestry5.ioc;
 
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Modifier;
-import java.net.URL;
-import java.net.URLClassLoader;
-
-import javassist.CannotCompileException;
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.CtConstructor;
-import javassist.CtMethod;
-import javassist.NotFoundException;
-
-import org.apache.tapestry5.ioc.services.ClassFabUtils;
+import com.example.*;
+import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
+import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
+import org.apache.tapestry5.internal.plastic.asm.MethodVisitor;
 import org.apache.tapestry5.ioc.test.IOCTestCase;
 import org.apache.tapestry5.services.UpdateListenerHub;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import com.example.Counter;
-import com.example.CounterImpl;
-import com.example.ReloadAwareModule;
-import com.example.ReloadModule;
-import com.example.ReloadableService;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import static org.apache.tapestry5.internal.plastic.asm.Opcodes.*;
 
 /**
  * Test the ability to perform live class reloading of a service implementation.
@@ -73,7 +66,7 @@ public class ReloadTest extends IOCTestC
         System.out.println("Reload classes dir: " + classesURL);
 
         classLoader = new URLClassLoader(new URL[]
-        { classesURL }, Thread.currentThread().getContextClassLoader());
+                {classesURL}, Thread.currentThread().getContextClassLoader());
 
         classFile = new File(classesDir, "com/example/ReloadableServiceImpl.class");
     }
@@ -113,18 +106,27 @@ public class ReloadTest extends IOCTestC
     @Test
     public void reload_a_base_class() throws Exception
     {
+        String baseClassInternalName = PlasticInternalUtils.toInternalName(BASE_CLASS);
+        String internalName = PlasticInternalUtils.toInternalName(CLASS);
+
         createImplementationClass(BASE_CLASS, "initial from base");
 
-        ClassPool pool = new ClassPool(null);
 
-        pool.appendSystemPath();
-        pool.appendClassPath(classesDir.getAbsolutePath());
+        ClassWriter cw = createClassWriter(internalName, baseClassInternalName, ACC_PUBLIC);
 
-        CtClass ctClass = pool.makeClass(CLASS);
+        // Add default constructor
 
-        ctClass.setSuperclass(pool.get(BASE_CLASS));
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, baseClassInternalName, "<init>", "()V");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
 
-        ctClass.writeFile(classesDir.getAbsolutePath());
+        cw.visitEnd();
+
+        writeBytecode(cw, internalName);
 
         Registry registry = createRegistry();
 
@@ -134,7 +136,7 @@ public class ReloadTest extends IOCTestC
 
         assertEquals(reloadable.getStatus(), "initial from base");
 
-        touch(new File(classesDir, ClassFabUtils.getPathForClassNamed(BASE_CLASS)));
+        touch(new File(pathForInternalName(baseClassInternalName)));
 
         createImplementationClass(BASE_CLASS, "updated from base");
 
@@ -167,8 +169,7 @@ public class ReloadTest extends IOCTestC
         {
             reloadable.getStatus();
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             assertMessageContains(ex, "Unable to reload", CLASS);
         }
@@ -242,8 +243,7 @@ public class ReloadTest extends IOCTestC
             reloadable.getStatus();
 
             unreachable();
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             assertEquals(ex.getMessage(),
                     "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor.");
@@ -257,46 +257,94 @@ public class ReloadTest extends IOCTestC
         createImplementationClass(CLASS, status);
     }
 
-    private void createImplementationClass(String className, String status) throws NotFoundException,
-            CannotCompileException, IOException
+    private void createImplementationClass(String className, String status) throws Exception
     {
-        ClassPool pool = new ClassPool(null);
+        String internalName = PlasticInternalUtils.toInternalName(className);
 
-        pool.appendSystemPath();
+        ClassWriter cw = createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC);
 
-        CtClass ctClass = pool.makeClass(className);
+        // Add default constructor
 
-        ctClass.addInterface(pool.get(ReloadableService.class.getName()));
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
 
-        CtMethod method = new CtMethod(pool.get("java.lang.String"), "getStatus", null, ctClass);
 
-        method.setBody(String.format("return \"%s\";", status));
+        mv = cw.visitMethod(ACC_PUBLIC, "getStatus", "()Ljava/lang/String;", null, null);
+        mv.visitCode();
+        mv.visitLdcInsn(status);
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
 
-        ctClass.addMethod(method);
+        cw.visitEnd();
 
-        ctClass.writeFile(classesDir.getAbsolutePath());
+        writeBytecode(cw, internalName);
     }
 
-    private void createInvalidImplentationClass() throws Exception
+    private ClassWriter createClassWriter(String internalName, String baseClassInternalName, int classModifiers)
+    {
+        ClassWriter cw = new ClassWriter(0);
+
+        cw.visit(V1_5, classModifiers, internalName, null,
+                baseClassInternalName, new String[]{
+                PlasticInternalUtils.toInternalName(ReloadableService.class.getName())
+        });
+
+        return cw;
+    }
+
+    private void writeBytecode(ClassWriter cw, String internalName) throws Exception
+    {
+        byte[] bytecode = cw.toByteArray();
+
+        writeBytecode(bytecode, pathForInternalName(internalName));
+    }
+
+    private String pathForInternalName(String internalName)
+    {
+        return String.format("%s/%s.class",
+                classesDir.getAbsolutePath(),
+                internalName);
+    }
+
+    private void writeBytecode(byte[] bytecode, String path) throws Exception
     {
-        ClassPool pool = new ClassPool(null);
+        File file = new File(path);
+
+        file.getParentFile().mkdirs();
+
+        OutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
 
-        pool.appendSystemPath();
+        stream.write(bytecode);
 
-        CtClass ctClass = pool.makeClass(CLASS);
+        stream.close();
+    }
+
+    private void createInvalidImplentationClass() throws Exception
+    {
+        String internalName = PlasticInternalUtils.toInternalName(CLASS);
 
-        ctClass.setModifiers(Modifier.ABSTRACT | Modifier.PUBLIC);
-        ctClass.addInterface(pool.get(ReloadableService.class.getName()));
+        ClassWriter cw = createClassWriter(internalName, "java/lang/Object", ACC_PUBLIC);
 
-        CtConstructor constructor = new CtConstructor(new CtClass[0], ctClass);
+        // Add default constructor
 
-        constructor.setBody("return $0;");
+        MethodVisitor mv = cw.visitMethod(ACC_PROTECTED, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
 
-        constructor.setModifiers(Modifier.PROTECTED);
+        // Notice the  class is abstract, so no implementation.
 
-        ctClass.addConstructor(constructor);
+        cw.visitEnd();
 
-        ctClass.writeFile(classesDir.getAbsolutePath());
+        writeBytecode(cw, internalName);
     }
 
     @Test

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImplTest.java?rev=1196363&r1=1196362&r2=1196363&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImplTest.java Tue Nov  1 23:10:13 2011
@@ -14,7 +14,6 @@
 
 package org.apache.tapestry5.ioc.internal;
 
-import org.apache.tapestry5.internal.plastic.ClassLoaderDelegate;
 import org.apache.tapestry5.internal.plastic.PlasticClassLoader;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
@@ -668,7 +667,7 @@ public class DefaultModuleDefImplTest ex
 
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
 
-        PlasticClassLoader plasticLoader = new PlasticClassLoader(loader, new NoopDelegate());
+        PlasticClassLoader plasticLoader = new PlasticClassLoader(loader, new NoopClassLoaderDelegate());
 
         return plasticLoader.defineClassWithBytecode("EnhancedSyntheticMethodModule", bytecode);
     }
@@ -677,16 +676,4 @@ public class DefaultModuleDefImplTest ex
     // marker annotation are
     // merged into the set specific to the service).
 
-    private static class NoopDelegate implements ClassLoaderDelegate
-    {
-        public boolean shouldInterceptClassLoading(String className)
-        {
-            return false;
-        }
-
-        public Class<?> loadAndTransformClass(String className) throws ClassNotFoundException
-        {
-            return null;
-        }
-    }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NoopClassLoaderDelegate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NoopClassLoaderDelegate.java?rev=1196363&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NoopClassLoaderDelegate.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NoopClassLoaderDelegate.java Tue Nov  1 23:10:13 2011
@@ -0,0 +1,30 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal;
+
+import org.apache.tapestry5.internal.plastic.ClassLoaderDelegate;
+
+public class NoopClassLoaderDelegate implements ClassLoaderDelegate
+{
+    public boolean shouldInterceptClassLoading(String className)
+    {
+        return false;
+    }
+
+    public Class<?> loadAndTransformClass(String className) throws ClassNotFoundException
+    {
+        throw new IllegalStateException();
+    }
+}