diff options
-rw-r--r-- | .classpath | 1 | ||||
-rw-r--r-- | Readme.html | 5 | ||||
-rw-r--r-- | src/main/javassist/ClassPool.java | 90 | ||||
-rw-r--r-- | src/main/javassist/CtClass.java | 36 | ||||
-rw-r--r-- | src/main/javassist/Loader.java | 18 | ||||
-rw-r--r-- | src/main/javassist/scopedpool/ScopedClassPool.java | 7 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/FactoryHelper.java | 54 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/ProxyFactory.java | 15 |
8 files changed, 199 insertions, 27 deletions
@@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry excluding="javassist/util/HotSwapper.java" kind="src" path="src/main"/> + <classpathentry kind="src" path="src/test"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="output" path="build/classes"/> </classpath> diff --git a/Readme.html b/Readme.html index f650a215..c791af92 100644 --- a/Readme.html +++ b/Readme.html @@ -283,6 +283,9 @@ see javassist.Dump. <p>-version 3.3 <ul> + <li>CtClass#toClass() and ClassPool#toClass() were modified to accept a + <code>ProtectionDomain</code> + (<a href="http://jira.jboss.com/jira/browse/JASSIST-23">JASSIST-23</a>). <li>CtClass#getAvailableAnnotations() etc. have been implemented. <li>A bug related to a way of dealing with a bridge method was fixed (<a href="http://jira.jboss.com/jira/browse/HIBERNATE-37">HIBERNATE-37</a>). @@ -683,7 +686,7 @@ Howard Lewis Ship, Richard Jones, Marjan Sterjev, Bruce McDonald, Mark Brennan, Vlad Skarzhevskyy, Brett Randall, Tsuyoshi Murakami, Nathan Meyers, Yoshiyuki Usui Yutaka Sunaga, Arjan van der Meer, Bruce Eckel, Guillaume Pothier, -Kumar Matcha, Andreas Salathe, +Kumar Matcha, Andreas Salathe, Renat Zubairov, and all other contributors for their contributions. <p><br> diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java index 1062d670..c65872c3 100644 --- a/src/main/javassist/ClassPool.java +++ b/src/main/javassist/ClassPool.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.security.ProtectionDomain; import java.util.Hashtable; import java.util.Iterator; import java.util.ArrayList; @@ -61,6 +62,24 @@ import javassist.bytecode.Descriptor; * @see javassist.ClassPath */ public class ClassPool { + // used by toClass(). + private static java.lang.reflect.Method defineClass1, defineClass2; + + static { + try { + Class cl = Class.forName("java.lang.ClassLoader"); + defineClass1 = cl.getDeclaredMethod("defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class }); + + defineClass2 = cl.getDeclaredMethod("defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class, ProtectionDomain.class }); + } + catch (Exception e) { + throw new RuntimeException("cannot initialize ClassPool"); + } + } /** * Determines the search order. @@ -752,21 +771,27 @@ public class ClassPool { * Once this method is called, further modifications are not * allowed any more. * To load the class, this method uses the context class loader - * of the current thread. If the program is running on some application - * server, the context class loader might be inappropriate to load the - * class. + * of the current thread. It is obtained by calling + * <code>getClassLoader()</code>. * - * <p>This can be changed by subclassing the pool and changing + * <p>This behavior can be changed by subclassing the pool and changing * the <code>getClassLoader()</code> method. + * If the program is running on some application + * server, the context class loader might be inappropriate to load the + * class. * * <p>This method is provided for convenience. If you need more * complex functionality, you should write your own class loader. * - * @see #toClass(CtClass, java.lang.ClassLoader) + * <p><b>Warining:</b> A Class object returned by this method may not + * work with a security manager or a signed jar file because a + * protection domain is not specified. + * + * @see #toClass(CtClass, java.lang.ClassLoader, ProtectionDomain) * @see #getClassLoader() */ public Class toClass(CtClass clazz) throws CannotCompileException { - return toClass(clazz, getClassLoader()); + return toClass(clazz, getClassLoader(), null); } /** @@ -793,6 +818,23 @@ public class ClassPool { /** * Converts the class to a <code>java.lang.Class</code> object. + * Do not override this method any more at a subclass because + * <code>toClass(CtClass)</code> never calls this method. + * + * <p><b>Warining:</b> A Class object returned by this method may not + * work with a security manager or a signed jar file because a + * protection domain is not specified. + * + * @deprecated Replaced by {@link #toClass(CtClass,ClassLoader,ProtectionDomain)} + */ + public final Class toClass(CtClass ct, ClassLoader loader) + throws CannotCompileException + { + return toClass(ct, loader, null); + } + + /** + * Converts the class to a <code>java.lang.Class</code> object. * Once this method is called, further modifications are not allowed * any more. * @@ -802,24 +844,44 @@ public class ClassPool { * on the class loader is invoked through the reflection API, * the caller must have permissions to do that. * + * <p>An easy way to obtain <code>ProtectionDomain</code> object is + * to call <code>getProtectionDomain()</code> + * in <code>java.lang.Class</code>. It returns the domain that the + * class belongs to. + * * <p>This method is provided for convenience. If you need more * complex functionality, you should write your own class loader. * * @param loader the class loader used to load this class. + * For example, the loader returned by + * <code>getClassLoader()</code> can be used + * for this parameter. + * @param domain the protection domain for the class. + * If it is null, the default domain created + * by <code>java.lang.ClassLoader</code> is used. + * + * @see #getContextClassLoader() + * @since 3.3 */ - public Class toClass(CtClass ct, ClassLoader loader) + public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) throws CannotCompileException { try { byte[] b = ct.toBytecode(); - Class cl = Class.forName("java.lang.ClassLoader"); - java.lang.reflect.Method method = - cl.getDeclaredMethod("defineClass", - new Class[] { String.class, byte[].class, - int.class, int.class }); + java.lang.reflect.Method method; + Object[] args; + if (domain == null) { + method = defineClass1; + args = new Object[] { ct.getName(), b, new Integer(0), + new Integer(b.length)}; + } + else { + method = defineClass2; + args = new Object[] { ct.getName(), b, new Integer(0), + new Integer(b.length), domain}; + } + method.setAccessible(true); - Object[] args = new Object[] { ct.getName(), b, new Integer(0), - new Integer(b.length)}; Class clazz = (Class)method.invoke(loader, args); method.setAccessible(false); return clazz; diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 51fa78c3..d7552002 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -23,6 +23,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; +import java.security.ProtectionDomain; import java.util.Collection; import javassist.bytecode.ClassFile; import javassist.bytecode.Descriptor; @@ -1025,6 +1026,10 @@ public abstract class CtClass { * <p>Note: this method calls <code>toClass()</code> * in <code>ClassPool</code>. * + * <p><b>Warining:</b> A Class object returned by this method may not + * work with a security manager or a signed jar file because a + * protection domain is not specified. + * * @see #toClass(java.lang.ClassLoader) * @see ClassPool#toClass(CtClass) */ @@ -1043,6 +1048,11 @@ public abstract class CtClass { * on the class loader is invoked through the reflection API, * the caller must have permissions to do that. * + * <p>An easy way to obtain <code>ProtectionDomain</code> object is + * to call <code>getProtectionDomain()</code> + * in <code>java.lang.Class</code>. It returns the domain that + * the class belongs to. + * * <p>This method is provided for convenience. If you need more * complex functionality, you should write your own class loader. * @@ -1050,9 +1060,33 @@ public abstract class CtClass { * in <code>ClassPool</code>. * * @param loader the class loader used to load this class. + * If it is null, the class loader returned by + * {@link ClassPool#getClassLoader()} is used. + * @param domain the protection domain that the class belongs to. + * If it is null, the default domain created + * by <code>java.lang.ClassLoader</code> is used. * @see ClassPool#toClass(CtClass,java.lang.ClassLoader) */ - public Class toClass(ClassLoader loader) + public Class toClass(ClassLoader loader, ProtectionDomain domain) + throws CannotCompileException + { + ClassPool cp = getClassPool(); + if (loader == null) + loader = cp.getClassLoader(); + + return cp.toClass(this, loader, domain); + } + + /** + * Converts this class to a <code>java.lang.Class</code> object. + * + * <p><b>Warining:</b> A Class object returned by this method may not + * work with a security manager or a signed jar file because a + * protection domain is not specified. + * + * @deprecated Replaced by {@link #toClass(ClassLoader,ProtectionDomain)} + */ + public final Class toClass(ClassLoader loader) throws CannotCompileException { return getClassPool().toClass(this, loader); diff --git a/src/main/javassist/Loader.java b/src/main/javassist/Loader.java index b676a63a..716fc988 100644 --- a/src/main/javassist/Loader.java +++ b/src/main/javassist/Loader.java @@ -18,6 +18,7 @@ package javassist; import java.io.*; import java.util.Hashtable; import java.util.Vector; +import java.security.ProtectionDomain; /** * The class loader for Javassist. @@ -136,6 +137,7 @@ public class Loader extends ClassLoader { private Vector notDefinedPackages; // must be atomic. private ClassPool source; private Translator translator; + private ProtectionDomain domain; /** * Specifies the algorithm of class loading. @@ -183,6 +185,7 @@ public class Loader extends ClassLoader { notDefinedPackages = new Vector(); source = cp; translator = null; + domain = null; delegateLoadingOf("javassist.Loader"); } @@ -202,6 +205,16 @@ public class Loader extends ClassLoader { } /** + * Sets the protection domain for the classes handled by this class + * loader. Without registering an appropriate protection domain, + * the program loaded by this loader will not work with a security + * manager or a signed jar file. + */ + public void setDomain(ProtectionDomain d) { + domain = d; + } + + /** * Sets the soruce <code>ClassPool</code>. */ public void setClassPool(ClassPool cp) { @@ -362,7 +375,10 @@ public class Loader extends ClassLoader { } } - return defineClass(name, classfile, 0, classfile.length); + if (domain == null) + return defineClass(name, classfile, 0, classfile.length); + else + return defineClass(name, classfile, 0, classfile.length, domain); } protected Class loadClassByDelegation(String name) diff --git a/src/main/javassist/scopedpool/ScopedClassPool.java b/src/main/javassist/scopedpool/ScopedClassPool.java index 4c33e634..8be4b439 100644 --- a/src/main/javassist/scopedpool/ScopedClassPool.java +++ b/src/main/javassist/scopedpool/ScopedClassPool.java @@ -16,6 +16,7 @@ package javassist.scopedpool; import java.lang.ref.WeakReference; +import java.security.ProtectionDomain; import java.util.Iterator; import java.util.Map; import javassist.CannotCompileException; @@ -30,7 +31,7 @@ import javassist.NotFoundException; * @author <a href="mailto:bill@jboss.org">Bill Burke</a> * @author <a href="adrian@jboss.com">Adrian Brock</a> * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> - * @version $Revision: 1.3 $ + * @version $Revision: 1.4 $ */ public class ScopedClassPool extends ClassPool { protected ScopedClassPoolRepository repository; @@ -261,7 +262,7 @@ public class ScopedClassPool extends ClassPool { * @throws CannotCompileException * for any error */ - public Class toClass(CtClass ct, ClassLoader loader) + public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) throws CannotCompileException { // We need to pass up the classloader stored in this pool, as the // default implementation uses the Thread context cl. @@ -276,6 +277,6 @@ public class ScopedClassPool extends ClassPool { // org.apache.jsp. For classes belonging to org.apache.jsp, // JasperLoader does NOT delegate to its parent if it cannot find them. lockInCache(ct); - return super.toClass(ct, getClassLoader0()); + return super.toClass(ct, getClassLoader0(), domain); } } diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java index b00b9a93..21038fe9 100644 --- a/src/main/javassist/util/proxy/FactoryHelper.java +++ b/src/main/javassist/util/proxy/FactoryHelper.java @@ -21,8 +21,10 @@ import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.security.ProtectionDomain; import javassist.CannotCompileException; +import javassist.CtClass; import javassist.bytecode.ClassFile; /** @@ -32,6 +34,24 @@ import javassist.bytecode.ClassFile; * @see ProxyFactory */ public class FactoryHelper { + private static java.lang.reflect.Method defineClass1, defineClass2; + + static { + try { + Class cl = Class.forName("java.lang.ClassLoader"); + defineClass1 = cl.getDeclaredMethod("defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class }); + + defineClass2 = cl.getDeclaredMethod("defineClass", + new Class[] { String.class, byte[].class, + int.class, int.class, ProtectionDomain.class }); + } + catch (Exception e) { + throw new RuntimeException("cannot initialize"); + } + } + /** * Returns an index for accessing arrays in this class. * @@ -101,19 +121,41 @@ public class FactoryHelper { /** * Loads a class file by a given class loader. + * This method uses a default protection domain for the class + * but it may not work with a security manager or a sigend jar file. + * + * @see #toClass(CtClass,ClassLoader,ProtectionDomain) */ public static Class toClass(ClassFile cf, ClassLoader loader) + throws CannotCompileException + { + return toClass(cf, loader, null); + } + + /** + * Loads a class file by a given class loader. + * + * @param domain if it is null, a default domain is used. + */ + public static Class toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain) throws CannotCompileException { try { byte[] b = toBytecode(cf); - Class cl = Class.forName("java.lang.ClassLoader"); - java.lang.reflect.Method method = cl.getDeclaredMethod( - "defineClass", new Class[] { String.class, byte[].class, - Integer.TYPE, Integer.TYPE }); + java.lang.reflect.Method method; + Object[] args; + if (domain == null) { + method = defineClass1; + args = new Object[] { cf.getName(), b, new Integer(0), + new Integer(b.length) }; + } + else { + method = defineClass2; + args = new Object[] { cf.getName(), b, new Integer(0), + new Integer(b.length), domain }; + } + method.setAccessible(true); - Object[] args = new Object[] { cf.getName(), b, new Integer(0), - new Integer(b.length) }; Class clazz = (Class)method.invoke(loader, args); method.setAccessible(false); return clazz; diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index bf29e539..fdd397ad 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -166,7 +167,7 @@ public class ProxyFactory { if (writeDirectory != null) FactoryHelper.writeFile(cf, writeDirectory); - thisClass = FactoryHelper.toClass(cf, cl); + thisClass = FactoryHelper.toClass(cf, cl, getDomain()); setHandler(); } catch (CannotCompileException e) { @@ -194,6 +195,18 @@ public class ProxyFactory { return loader; } + protected ProtectionDomain getDomain() { + Class clazz; + if (superClass != null && !superClass.getName().equals("java.lang.Object")) + clazz = superClass; + else if (interfaces != null && interfaces.length > 0) + clazz = interfaces[0]; + else + clazz = this.getClass(); + + return clazz.getProtectionDomain(); + } + /** * Creates a proxy class and returns an instance of that class. * |