diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-08-07 15:48:31 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-08-07 15:48:31 +0000 |
commit | 2405e6804619f75ef93c9a8e9ba366e595f4899d (patch) | |
tree | a5fac709b60ce7e9f161fe5b55e144e24283cdcf /src/main | |
parent | a62c5816078737cc3a392beaa88c2c03d95ea961 (diff) | |
download | javassist-2405e6804619f75ef93c9a8e9ba366e595f4899d.tar.gz javassist-2405e6804619f75ef93c9a8e9ba366e595f4899d.zip |
fixed the bug reported as JASSIST-23.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@305 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main')
-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 |
6 files changed, 194 insertions, 26 deletions
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. * |