git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@305 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -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> |
@@ -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> |
@@ -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); | |||
} | |||
/** | |||
@@ -791,6 +816,23 @@ public class ClassPool { | |||
return Thread.currentThread().getContextClassLoader(); | |||
} | |||
/** | |||
* 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 | |||
@@ -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; |
@@ -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); |
@@ -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"); | |||
} | |||
@@ -201,6 +204,16 @@ public class Loader extends ClassLoader { | |||
notDefinedHere.put(classname, this); | |||
} | |||
/** | |||
* 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>. | |||
*/ | |||
@@ -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) |
@@ -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); | |||
} | |||
} |
@@ -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; |
@@ -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. | |||
* |