git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@233 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
<ul><pre> | <ul><pre> | ||||
% javac sample/reflect/*.java | % javac sample/reflect/*.java | ||||
% java javassist.reflect.Loader sample.reflect.Main Joe | |||||
% java javassist.tools.reflect.Loader sample.reflect.Main Joe | |||||
</pre></ul> | </pre></ul> | ||||
<p>Compare this result with that of the regular execution without reflection: | <p>Compare this result with that of the regular execution without reflection: | ||||
To do this, type the commands: | To do this, type the commands: | ||||
<ul><pre> | <ul><pre> | ||||
% java javassist.reflect.Compiler sample.reflect.Person -m sample.reflect.VerboseMetaobj | |||||
% java javassist.tools.reflect.Compiler sample.reflect.Person -m sample.reflect.VerboseMetaobj | |||||
</pre></ul> | </pre></ul> | ||||
<p> Then, | <p> Then, | ||||
<li>The return type of CtClass.stopPruning() was changed from void | <li>The return type of CtClass.stopPruning() was changed from void | ||||
to boolean. | to boolean. | ||||
<li>toMethod() in javassist.CtConstructor has been implemented. | <li>toMethod() in javassist.CtConstructor has been implemented. | ||||
<li>javassist.preproc package was elminated and the source was | |||||
moved to the sample directory. | |||||
</ul> | |||||
<p>- version 3.1 | |||||
<ul> | |||||
<li>javassist.tool package was renamed to javassist.tools. | |||||
<li>It includes new javassist.util.proxy package | |||||
similar to Enhancer of CGLIB. | |||||
<p> | |||||
<li>The subpackages of Javassist were restructured. | |||||
<ul> | |||||
<li>javassist.tool package was renamed to javassist.tools. | |||||
<li>HotSwapper was moved to javassist.util. | |||||
<li>Several subpackages were moved to javassist.tools. | |||||
<li>javassist.preproc package was elminated and the source was | |||||
moved to the sample directory. | |||||
</ul> | |||||
</ul> | </ul> | ||||
<p>- version 3.1 RC2 in September 7, 2005 | <p>- version 3.1 RC2 in September 7, 2005 |
excludepackagenames="javassist.compiler.*,javassist.convert.*" | excludepackagenames="javassist.compiler.*,javassist.convert.*" | ||||
sourcepath="src/main" | sourcepath="src/main" | ||||
defaultexcludes="yes" | defaultexcludes="yes" | ||||
locale="en_US" | |||||
charset="iso-8859-1" | |||||
destdir="html" | destdir="html" | ||||
author="true" | author="true" | ||||
version="true" | version="true" | ||||
use="true" | use="true" | ||||
Locale="en_US" | |||||
charset="iso-8859-1" | |||||
Public="true" | |||||
public="true" | |||||
nohelp="true" | nohelp="true" | ||||
windowtitle="Javassist API"> | windowtitle="Javassist API"> | ||||
<doctitle><![CDATA[<h1>Javassist</h1>]]></doctitle> | <doctitle><![CDATA[<h1>Javassist</h1>]]></doctitle> | ||||
<bottom><![CDATA[<i>Javassist, a Java-bytecode translator toolkit. | <bottom><![CDATA[<i>Javassist, a Java-bytecode translator toolkit. | ||||
Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||||
Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||||
</javadoc> | </javadoc> | ||||
</target> | </target> | ||||
<target name = "sample-all" | <target name = "sample-all" | ||||
depends="sample-test,sample-reflect,sample-duplicate,sample-vector"> | depends="sample-test,sample-reflect,sample-duplicate,sample-vector"> | ||||
<echo>** please run sample-rmi and sample-evolve separately **</echo> | |||||
<echo>** please run sample-rmi, sample-evolve, and</echo> | |||||
<echo> sample-hotswap (or -hotswap5) separately **</echo> | |||||
</target> | </target> | ||||
<target name = "sample-test" depends="sample" > | <target name = "sample-test" depends="sample" > | ||||
</target> | </target> | ||||
<target name = "sample-reflect" depends="sample" > | <target name = "sample-reflect" depends="sample" > | ||||
<java fork="true" dir="${run.dir}" classname="javassist.reflect.Loader"> | |||||
<java fork="true" dir="${run.dir}" classname="javassist.tools.reflect.Loader"> | |||||
<classpath refid="classpath"/> | <classpath refid="classpath"/> | ||||
<arg line="sample.reflect.Main Joe" /> | <arg line="sample.reflect.Main Joe" /> | ||||
</java> | </java> | ||||
<!-- for JDK 1.4 --> | <!-- for JDK 1.4 --> | ||||
<target name = "sample-hotswap" depends="sample"> | <target name = "sample-hotswap" depends="sample"> | ||||
<echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo> | <echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo> | ||||
<echo>** for JDK 1.4</echo> | |||||
<java fork="true" dir="${run.dir}" classname="Test"> | <java fork="true" dir="${run.dir}" classname="Test"> | ||||
<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000" /> | <jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000" /> | ||||
<classpath refid="classpath"/> | <classpath refid="classpath"/> | ||||
<!-- for Java 5 --> | <!-- for Java 5 --> | ||||
<target name = "sample-hotswap5" depends="sample"> | <target name = "sample-hotswap5" depends="sample"> | ||||
<echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo> | <echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo> | ||||
<echo>** for JDK 1.5 or later</echo> | |||||
<java fork="true" dir="${run.dir}" classname="Test"> | <java fork="true" dir="${run.dir}" classname="Test"> | ||||
<jvmarg line="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000" /> | <jvmarg line="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000" /> | ||||
<classpath refid="classpath"/> | <classpath refid="classpath"/> |
package sample.duplicate; | package sample.duplicate; | ||||
import javassist.reflect.*; | |||||
import javassist.tools.reflect.*; | |||||
public class DuplicatedObject extends Metaobject { | public class DuplicatedObject extends Metaobject { | ||||
private DuplicatedObject backup; | private DuplicatedObject backup; |
/* | /* | ||||
Runtime metaobject (JDK 1.2 or later only). | Runtime metaobject (JDK 1.2 or later only). | ||||
With the javassist.reflect package, the users can attach a metaobject | |||||
With the javassist.tools.reflect package, the users can attach a metaobject | |||||
to an object. The metaobject can control the behavior of the object. | to an object. The metaobject can control the behavior of the object. | ||||
For example, you can implement fault tolerancy with this ability. One | For example, you can implement fault tolerancy with this ability. One | ||||
of the implementation techniques of fault tolernacy is to make a copy | of the implementation techniques of fault tolernacy is to make a copy | ||||
% java sample.duplicate.Main | % java sample.duplicate.Main | ||||
You would see two balls in a window. This is because | You would see two balls in a window. This is because | ||||
sample.duplicate.Viewer is loaded by javassist.reflect.Loader so that | |||||
sample.duplicate.Viewer is loaded by javassist.tools.reflect.Loader so that | |||||
a metaobject would be attached. | a metaobject would be attached. | ||||
*/ | */ | ||||
public class Main { | public class Main { | ||||
public static void main(String[] args) throws Throwable { | public static void main(String[] args) throws Throwable { | ||||
javassist.reflect.Loader cl = new javassist.reflect.Loader(); | |||||
javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader(); | |||||
cl.makeReflective("sample.duplicate.Ball", | cl.makeReflective("sample.duplicate.Ball", | ||||
"sample.duplicate.DuplicatedObject", | "sample.duplicate.DuplicatedObject", | ||||
"javassist.reflect.ClassMetaobject"); | |||||
"javassist.tools.reflect.ClassMetaobject"); | |||||
cl.run("sample.duplicate.Viewer", args); | cl.run("sample.duplicate.Viewer", args); | ||||
} | } | ||||
} | } |
package sample.evolve; | package sample.evolve; | ||||
import javassist.web.*; | |||||
import javassist.tools.web.*; | |||||
import java.io.*; | import java.io.*; | ||||
/** | /** |
private void onLoadUpdatable(String classname) throws NotFoundException, | private void onLoadUpdatable(String classname) throws NotFoundException, | ||||
CannotCompileException { | CannotCompileException { | ||||
// if the class is a concrete class, | // if the class is a concrete class, | ||||
// classname is <updatableClassName>$<version>. | |||||
// classname is <updatableClassName>$$<version>. | |||||
int i = classname.lastIndexOf('$'); | |||||
int i = classname.lastIndexOf("$$"); | |||||
if (i <= 0) | if (i <= 0) | ||||
return; | return; | ||||
int version; | int version; | ||||
try { | try { | ||||
version = Integer.parseInt(classname.substring(i + 1)); | |||||
version = Integer.parseInt(classname.substring(i + 2)); | |||||
} | } | ||||
catch (NumberFormatException e) { | catch (NumberFormatException e) { | ||||
throw new NotFoundException(classname, e); | throw new NotFoundException(classname, e); |
else | else | ||||
version = ((Integer)found).intValue() + 1; | version = ((Integer)found).intValue() + 1; | ||||
Class c = Class.forName(qualifiedClassname + '$' + version); | |||||
Class c = Class.forName(qualifiedClassname + "$$" + version); | |||||
versionNo.put(qualifiedClassname, new Integer(version)); | versionNo.put(qualifiedClassname, new Integer(version)); | ||||
return c; | return c; | ||||
} | } |
import java.io.*; | import java.io.*; | ||||
import javassist.tools.HotSwapper; | |||||
import javassist.util.HotSwapper; | |||||
public class Test { | public class Test { | ||||
public static void main(String[] args) throws Exception { | public static void main(String[] args) throws Exception { |
package sample.reflect; | package sample.reflect; | ||||
import javassist.reflect.Loader; | |||||
import javassist.tools.reflect.Loader; | |||||
/* | /* | ||||
The "verbose metaobject" example (JDK 1.2 or later only). | The "verbose metaobject" example (JDK 1.2 or later only). | ||||
To run, | To run, | ||||
% java javassist.reflect.Loader sample.reflect.Main Joe | |||||
% java javassist.tools.reflect.Loader sample.reflect.Main Joe | |||||
Compare this result with that of the regular execution without reflection: | Compare this result with that of the regular execution without reflection: | ||||
Loader cl = (Loader)Main.class.getClassLoader(); | Loader cl = (Loader)Main.class.getClassLoader(); | ||||
cl.makeReflective("sample.reflect.Person", | cl.makeReflective("sample.reflect.Person", | ||||
"sample.reflect.VerboseMetaobj", | "sample.reflect.VerboseMetaobj", | ||||
"javassist.reflect.ClassMetaobject"); | |||||
"javassist.tools.reflect.ClassMetaobject"); | |||||
cl.run("sample.reflect.Person", args); | cl.run("sample.reflect.Person", args); | ||||
} | } |
package sample.reflect; | package sample.reflect; | ||||
import javassist.reflect.Metalevel; | |||||
import javassist.reflect.Metaobject; | |||||
import javassist.tools.reflect.Metalevel; | |||||
import javassist.tools.reflect.Metaobject; | |||||
public class Person { | public class Person { | ||||
public String name; | public String name; |
package sample.reflect; | package sample.reflect; | ||||
import javassist.reflect.*; | |||||
import javassist.tools.reflect.*; | |||||
public class VerboseMetaobj extends Metaobject { | public class VerboseMetaobj extends Metaobject { | ||||
public VerboseMetaobj(Object self, Object[] args) { | public VerboseMetaobj(Object self, Object[] args) { |
import java.applet.*; | import java.applet.*; | ||||
import java.awt.*; | import java.awt.*; | ||||
import java.awt.event.*; | import java.awt.event.*; | ||||
import javassist.rmi.ObjectImporter; | |||||
import javassist.rmi.ObjectNotFoundException; | |||||
import javassist.web.Viewer; | |||||
import javassist.tools.rmi.ObjectImporter; | |||||
import javassist.tools.rmi.ObjectNotFoundException; | |||||
import javassist.tools.web.Viewer; | |||||
public class CountApplet extends Applet implements ActionListener { | public class CountApplet extends Applet implements ActionListener { | ||||
private Font font; | private Font font; |
package sample.rmi; | package sample.rmi; | ||||
import javassist.rmi.AppletServer; | |||||
import javassist.tools.rmi.AppletServer; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import javassist.CannotCompileException; | import javassist.CannotCompileException; | ||||
import javassist.NotFoundException; | import javassist.NotFoundException; |
<p>If you don't want to use a web browser, do as follows: | <p>If you don't want to use a web browser, do as follows: | ||||
<ul><pre>% java javassist.web.Viewer localhost 5001 sample.rmi.CountApplet</pre></ul> | |||||
<ul><pre>% java javassist.tools.web.Viewer localhost 5001 sample.rmi.CountApplet</pre></ul> |
local object. The applet can communicate through a socket with the | local object. The applet can communicate through a socket with the | ||||
host that executes the web server distributing that applet. However, | host that executes the web server distributing that applet. However, | ||||
the applet cannot directly call a method on an object if the object is | the applet cannot directly call a method on an object if the object is | ||||
on a remote host. The <code>javassist.rmi</code> package provides | |||||
on a remote host. The <code>javassist.tools.rmi</code> package provides | |||||
a mechanism for the applet to transparently access the remote object. | a mechanism for the applet to transparently access the remote object. | ||||
The rules that the applet must be subject to are simpler than the | The rules that the applet must be subject to are simpler than the | ||||
standard Java RMI. | standard Java RMI. | ||||
<p><b>Figure 1: Applet</b> | <p><b>Figure 1: Applet</b> | ||||
<pre> | <pre> | ||||
<font color="red">import javassist.rmi.ObjectImporter;</font> | |||||
<font color="red">import javassist.tools.rmi.ObjectImporter;</font> | |||||
public class CountApplet extends Applet implements ActionListener { | public class CountApplet extends Applet implements ActionListener { | ||||
private Font font; | private Font font; | ||||
} | } | ||||
</pre> | </pre> | ||||
<p>Note that the <code>javassist.rmi</code> package does not require | |||||
<p>Note that the <code>javassist.tools.rmi</code> package does not require | |||||
the <code>Counter</code> class to be an interface unlike the Java RMI, | the <code>Counter</code> class to be an interface unlike the Java RMI, | ||||
with which <code>Counter</code> must be an interface and it must be | with which <code>Counter</code> must be an interface and it must be | ||||
implemented by another class. | implemented by another class. | ||||
<p> With the Java RMI or Voyager, the applet programmer must define | <p> With the Java RMI or Voyager, the applet programmer must define | ||||
an interface for every remote object class and access the remote object | an interface for every remote object class and access the remote object | ||||
through that interface. | through that interface. | ||||
On the other hand, the <code>javassist.rmi</code> package does not | |||||
On the other hand, the <code>javassist.tools.rmi</code> package does not | |||||
require the programmer to follow that programming convention. | require the programmer to follow that programming convention. | ||||
It is suitable for writing simple distributed programs like applets. | It is suitable for writing simple distributed programs like applets. | ||||
* | * | ||||
* @param name method name | * @param name method name | ||||
* @param desc method descriptor | * @param desc method descriptor | ||||
* @see CtBehavior.getSignature() | |||||
* @see CtBehavior#getSignature() | |||||
* @see javassist.bytecode.Descriptor | * @see javassist.bytecode.Descriptor | ||||
*/ | */ | ||||
public CtMethod getMethod(String name, String desc) | public CtMethod getMethod(String name, String desc) |
* | * | ||||
* @param src the source text. | * @param src the source text. | ||||
* @param declaring the class to which the created method is added. | * @param declaring the class to which the created method is added. | ||||
* @see CtNewMethod.make(String, CtClass) | |||||
* @see CtNewMethod#make(String, CtClass) | |||||
*/ | */ | ||||
public static CtMethod make(String src, CtClass declaring) | public static CtMethod make(String src, CtClass declaring) | ||||
throws CannotCompileException | throws CannotCompileException |
* Appends PUTSTATIC. | * Appends PUTSTATIC. | ||||
* | * | ||||
* @param classname the fully-qualified name of the target class. | * @param classname the fully-qualified name of the target class. | ||||
* @param filedName the field name. | |||||
* @param fieldName the field name. | |||||
* @param desc the descriptor of the field type. | * @param desc the descriptor of the field type. | ||||
*/ | */ | ||||
public void addPutstatic(String classname, String fieldName, String desc) { | public void addPutstatic(String classname, String fieldName, String desc) { |
/** | /** | ||||
* Returns the first character of the current element. | * Returns the first character of the current element. | ||||
* @return | |||||
*/ | */ | ||||
public char currentChar() { return desc.charAt(curPos); } | public char currentChar() { return desc.charAt(curPos); } | ||||
<html> | <html> | ||||
<body> | <body> | ||||
Annotations API. | |||||
Bytecode-level Annotations API. | |||||
<p>This package provides low-level API for editing annotations attributes. | <p>This package provides low-level API for editing annotations attributes. | ||||
* The method signature is represented by a character string | * The method signature is represented by a character string | ||||
* called method descriptor, which is defined in the JVM specification. | * called method descriptor, which is defined in the JVM specification. | ||||
* | * | ||||
* @see javassist.CtBehavior.getSignature() | |||||
* @see javassist.CtBehavior#getSignature() | |||||
* @see javassist.bytecode.Descriptor | * @see javassist.bytecode.Descriptor | ||||
* @since 3.1 | * @since 3.1 | ||||
*/ | */ |
<html> | <html> | ||||
<body> | <body> | ||||
Utility classes. | |||||
Covenient tools. | |||||
</body> | </body> | ||||
</html> | </html> |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
/** | /** | ||||
* Signals that <code>ClassMetaobject.newInstance()</code> fails. | * Signals that <code>ClassMetaobject.newInstance()</code> fails. |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
import java.lang.IllegalAccessException; | import java.lang.IllegalAccessException; | ||||
* Thrown when method invocation using the reflection API has thrown | * Thrown when method invocation using the reflection API has thrown | ||||
* an exception. | * an exception. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject#trapMethodcall(int, Object[]) | |||||
* @see javassist.reflect.ClassMetaobject#trapMethodcall(int, Object[]) | |||||
* @see javassist.reflect.ClassMetaobject#invoke(Object, int, Object[]) | |||||
* @see javassist.tools.reflect.Metaobject#trapMethodcall(int, Object[]) | |||||
* @see javassist.tools.reflect.ClassMetaobject#trapMethodcall(int, Object[]) | |||||
* @see javassist.tools.reflect.ClassMetaobject#invoke(Object, int, Object[]) | |||||
*/ | */ | ||||
public class CannotInvokeException extends RuntimeException { | public class CannotInvokeException extends RuntimeException { | ||||
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import javassist.CannotCompileException; | import javassist.CannotCompileException; | ||||
* either ClassMetaobject or Metaobject. | * either ClassMetaobject or Metaobject. | ||||
* | * | ||||
* @author Brett Randall | * @author Brett Randall | ||||
* @see javassist.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass) | |||||
* @see javassist.tools.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass) | |||||
* @see javassist.CannotCompileException | * @see javassist.CannotCompileException | ||||
*/ | */ | ||||
public class CannotReflectException extends CannotCompileException { | public class CannotReflectException extends CannotCompileException { |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import java.lang.reflect.*; | import java.lang.reflect.*; | ||||
import java.util.Arrays; | import java.util.Arrays; | ||||
* <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass(); | * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass(); | ||||
* </pre></ul> | * </pre></ul> | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.Metalevel | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.Metalevel | |||||
*/ | */ | ||||
public class ClassMetaobject implements Serializable { | public class ClassMetaobject implements Serializable { | ||||
/** | /** |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import javassist.CtClass; | import javassist.CtClass; | ||||
import javassist.ClassPool; | import javassist.ClassPool; | ||||
* <p>This translator directly modifies class files on a local disk so that | * <p>This translator directly modifies class files on a local disk so that | ||||
* the classes represented by those class files are reflective. | * the classes represented by those class files are reflective. | ||||
* After the modification, the class files can be run with the standard JVM | * After the modification, the class files can be run with the standard JVM | ||||
* without <code>javassist.reflect.Loader</code> | |||||
* without <code>javassist.tools.reflect.Loader</code> | |||||
* or any other user-defined class loader. | * or any other user-defined class loader. | ||||
* | * | ||||
* <p>The modified class files are given as the command-line parameters, | * <p>The modified class files are given as the command-line parameters, | ||||
* <p>Note that if the super class is also made reflective, it must be done | * <p>Note that if the super class is also made reflective, it must be done | ||||
* before the sub class. | * before the sub class. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.reflect.Reflection | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Reflection | |||||
*/ | */ | ||||
public class Compiler { | public class Compiler { | ||||
String metaobj, classobj; | String metaobj, classobj; | ||||
if (entries[i].metaobject == null) | if (entries[i].metaobject == null) | ||||
metaobj = "javassist.reflect.Metaobject"; | |||||
metaobj = "javassist.tools.reflect.Metaobject"; | |||||
else | else | ||||
metaobj = entries[i].metaobject; | metaobj = entries[i].metaobject; | ||||
if (entries[i].classobject == null) | if (entries[i].classobject == null) | ||||
classobj = "javassist.reflect.ClassMetaobject"; | |||||
classobj = "javassist.tools.reflect.ClassMetaobject"; | |||||
else | else | ||||
classobj = entries[i].classobject; | classobj = entries[i].classobject; | ||||
} | } | ||||
private static void help(PrintStream out) { | private static void help(PrintStream out) { | ||||
out.println("Usage: java javassist.reflect.Compiler"); | |||||
out.println("Usage: java javassist.tools.reflect.Compiler"); | |||||
out.println(" (<class> [-m <metaobject>] [-c <class metaobject>])+"); | out.println(" (<class> [-m <metaobject>] [-c <class metaobject>])+"); | ||||
} | } | ||||
} | } |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import javassist.CannotCompileException; | import javassist.CannotCompileException; | ||||
import javassist.NotFoundException; | import javassist.NotFoundException; | ||||
* <ul><pre> | * <ul><pre> | ||||
* public class Main { | * public class Main { | ||||
* public static void main(String[] args) throws Throwable { | * public static void main(String[] args) throws Throwable { | ||||
* javassist.reflect.Loader cl | |||||
* = (javassist.reflect.Loader)Main.class.getClassLoader(); | |||||
* javassist.tools.reflect.Loader cl | |||||
* = (javassist.tools.reflect.Loader)Main.class.getClassLoader(); | |||||
* cl.makeReflective("Person", "MyMetaobject", | * cl.makeReflective("Person", "MyMetaobject", | ||||
* "javassist.reflect.ClassMetaobject"); | |||||
* "javassist.tools.reflect.ClassMetaobject"); | |||||
* cl.run("MyApp", args); | * cl.run("MyApp", args); | ||||
* } | * } | ||||
* } | * } | ||||
* | * | ||||
* <p>Then run this program as follows: | * <p>Then run this program as follows: | ||||
* | * | ||||
* <ul><pre>% java javassist.reflect.Loader Main arg1, ...</pre></ul> | |||||
* <ul><pre>% java javassist.tools.reflect.Loader Main arg1, ...</pre></ul> | |||||
* | * | ||||
* <p>This command runs <code>Main.main()</code> with <code>arg1</code>, ... | * <p>This command runs <code>Main.main()</code> with <code>arg1</code>, ... | ||||
* and <code>Main.main()</code> runs <code>MyApp.main()</code> with | * and <code>Main.main()</code> runs <code>MyApp.main()</code> with | ||||
* <ul><pre> | * <ul><pre> | ||||
* public class Main2 { | * public class Main2 { | ||||
* public static void main(String[] args) throws Throwable { | * public static void main(String[] args) throws Throwable { | ||||
* javassist.reflect.Loader cl = new javassist.reflect.Loader(); | |||||
* javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader(); | |||||
* cl.makeReflective("Person", "MyMetaobject", | * cl.makeReflective("Person", "MyMetaobject", | ||||
* "javassist.reflect.ClassMetaobject"); | |||||
* "javassist.tools.reflect.ClassMetaobject"); | |||||
* cl.run("MyApp", args); | * cl.run("MyApp", args); | ||||
* } | * } | ||||
* } | * } | ||||
* <ul><pre>% java Main2 arg1, ...</pre></ul> | * <ul><pre>% java Main2 arg1, ...</pre></ul> | ||||
* | * | ||||
* <p>The difference from the former one is that the class <code>Main</code> | * <p>The difference from the former one is that the class <code>Main</code> | ||||
* is loaded by <code>javassist.reflect.Loader</code> whereas the class | |||||
* is loaded by <code>javassist.tools.reflect.Loader</code> whereas the class | |||||
* <code>Main2</code> is not. Thus, <code>Main</code> belongs | * <code>Main2</code> is not. Thus, <code>Main</code> belongs | ||||
* to the same name space (security domain) as <code>MyApp</code> | * to the same name space (security domain) as <code>MyApp</code> | ||||
* whereas <code>Main2</code> does not; <code>Main2</code> belongs | * whereas <code>Main2</code> does not; <code>Main2</code> belongs | ||||
* to the same name space as <code>javassist.reflect.Loader</code>. | |||||
* to the same name space as <code>javassist.tools.reflect.Loader</code>. | |||||
* For more details, | * For more details, | ||||
* see the notes in the manual page of <code>javassist.Loader</code>. | * see the notes in the manual page of <code>javassist.Loader</code>. | ||||
* | * | ||||
* javassist.Loader cl | * javassist.Loader cl | ||||
* = new javassist.Loader(ClassPool.getDefault(reflection)); | * = new javassist.Loader(ClassPool.getDefault(reflection)); | ||||
* reflection.makeReflective("Person", "MyMetaobject", | * reflection.makeReflective("Person", "MyMetaobject", | ||||
* "javassist.reflect.ClassMetaobject"); | |||||
* "javassist.tools.reflect.ClassMetaobject"); | |||||
* cl.run("MyApp", args); | * cl.run("MyApp", args); | ||||
* } | * } | ||||
* } | * } | ||||
* | * | ||||
* <p><b>Note:</b> | * <p><b>Note:</b> | ||||
* | * | ||||
* <p><code>javassist.reflect.Loader</code> does not make a class reflective | |||||
* <p><code>javassist.tools.reflect.Loader</code> does not make a class reflective | |||||
* if that class is in a <code>java.*</code> or | * if that class is in a <code>java.*</code> or | ||||
* <code>javax.*</code> pacakge because of the specifications | * <code>javax.*</code> pacakge because of the specifications | ||||
* on the class loading algorithm of Java. The JVM does not allow to | * on the class loading algorithm of Java. The JVM does not allow to | ||||
* load such a system class with a user class loader. | * load such a system class with a user class loader. | ||||
* | * | ||||
* <p>To avoid this limitation, those classes should be statically | * <p>To avoid this limitation, those classes should be statically | ||||
* modified with <code>javassist.reflect.Compiler</code> and the original | |||||
* modified with <code>javassist.tools.reflect.Compiler</code> and the original | |||||
* class files should be replaced. | * class files should be replaced. | ||||
* | * | ||||
* @see javassist.reflect.Reflection | |||||
* @see javassist.reflect.Compiler | |||||
* @see javassist.tools.reflect.Reflection | |||||
* @see javassist.tools.reflect.Compiler | |||||
* @see javassist.Loader | * @see javassist.Loader | ||||
*/ | */ | ||||
public class Loader extends javassist.Loader { | public class Loader extends javassist.Loader { | ||||
*/ | */ | ||||
public Loader() throws CannotCompileException, NotFoundException { | public Loader() throws CannotCompileException, NotFoundException { | ||||
super(); | super(); | ||||
delegateLoadingOf("javassist.reflect.Loader"); | |||||
delegateLoadingOf("javassist.tools.reflect.Loader"); | |||||
reflection = new Reflection(); | reflection = new Reflection(); | ||||
ClassPool pool = ClassPool.getDefault(); | ClassPool pool = ClassPool.getDefault(); | ||||
* <code>ClassMetaobject</code>. | * <code>ClassMetaobject</code>. | ||||
* @return <code>false</code> if the class is already reflective. | * @return <code>false</code> if the class is already reflective. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
*/ | */ | ||||
public boolean makeReflective(String clazz, | public boolean makeReflective(String clazz, | ||||
String metaobject, String metaclass) | String metaobject, String metaclass) |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
/** | /** | ||||
* An interface to access a metaobject and a class metaobject. | * An interface to access a metaobject and a class metaobject. |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.io.Serializable; | import java.io.Serializable; | ||||
* <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject(); | * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject(); | ||||
* </pre></ul> | * </pre></ul> | ||||
* | * | ||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.reflect.Metalevel | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metalevel | |||||
*/ | */ | ||||
public class Metaobject implements Serializable { | public class Metaobject implements Serializable { | ||||
protected ClassMetaobject classmetaobject; | protected ClassMetaobject classmetaobject; | ||||
/** | /** | ||||
* Obtains the class metaobject associated with this metaobject. | * Obtains the class metaobject associated with this metaobject. | ||||
* | * | ||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
*/ | */ | ||||
public final ClassMetaobject getClassMetaobject() { | public final ClassMetaobject getClassMetaobject() { | ||||
return classmetaobject; | return classmetaobject; |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
import javassist.*; | import javassist.*; | ||||
import javassist.CtMethod.ConstParameter; | import javassist.CtMethod.ConstParameter; | ||||
* } | * } | ||||
* </pre></ul> | * </pre></ul> | ||||
* | * | ||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.Loader | |||||
* @see javassist.reflect.Compiler | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.Loader | |||||
* @see javassist.tools.reflect.Compiler | |||||
*/ | */ | ||||
public class Reflection implements Translator { | public class Reflection implements Translator { | ||||
static final String readPrefix = "_r_"; | static final String readPrefix = "_r_"; | ||||
static final String writePrefix = "_w_"; | static final String writePrefix = "_w_"; | ||||
static final String metaobjectClassName = "javassist.reflect.Metaobject"; | |||||
static final String metaobjectClassName = "javassist.tools.reflect.Metaobject"; | |||||
static final String classMetaobjectClassName | static final String classMetaobjectClassName | ||||
= "javassist.reflect.ClassMetaobject"; | |||||
= "javassist.tools.reflect.ClassMetaobject"; | |||||
protected CtMethod trapMethod, trapStaticMethod; | protected CtMethod trapMethod, trapStaticMethod; | ||||
protected CtMethod trapRead, trapWrite; | protected CtMethod trapRead, trapWrite; | ||||
public void start(ClassPool pool) throws NotFoundException { | public void start(ClassPool pool) throws NotFoundException { | ||||
classPool = pool; | classPool = pool; | ||||
final String msg | final String msg | ||||
= "javassist.reflect.Sample is not found or broken."; | |||||
= "javassist.tools.reflect.Sample is not found or broken."; | |||||
try { | try { | ||||
CtClass c = classPool.get("javassist.reflect.Sample"); | |||||
CtClass c = classPool.get("javassist.tools.reflect.Sample"); | |||||
trapMethod = c.getDeclaredMethod("trap"); | trapMethod = c.getDeclaredMethod("trap"); | ||||
trapStaticMethod = c.getDeclaredMethod("trapStatic"); | trapStaticMethod = c.getDeclaredMethod("trapStatic"); | ||||
trapRead = c.getDeclaredMethod("trapRead"); | trapRead = c.getDeclaredMethod("trapRead"); | ||||
* @param metaclass the class name of the class metaobject. | * @param metaclass the class name of the class metaobject. | ||||
* @return <code>false</code> if the class is already reflective. | * @return <code>false</code> if the class is already reflective. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
*/ | */ | ||||
public boolean makeReflective(String classname, | public boolean makeReflective(String classname, | ||||
String metaobject, String metaclass) | String metaobject, String metaclass) | ||||
* <code>ClassMetaobject</code>. | * <code>ClassMetaobject</code>. | ||||
* @return <code>false</code> if the class is already reflective. | * @return <code>false</code> if the class is already reflective. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
*/ | */ | ||||
public boolean makeReflective(Class clazz, | public boolean makeReflective(Class clazz, | ||||
Class metaobject, Class metaclass) | Class metaobject, Class metaclass) | ||||
* <code>ClassMetaobject</code>. | * <code>ClassMetaobject</code>. | ||||
* @return <code>false</code> if the class is already reflective. | * @return <code>false</code> if the class is already reflective. | ||||
* | * | ||||
* @see javassist.reflect.Metaobject | |||||
* @see javassist.reflect.ClassMetaobject | |||||
* @see javassist.tools.reflect.Metaobject | |||||
* @see javassist.tools.reflect.ClassMetaobject | |||||
*/ | */ | ||||
public boolean makeReflective(CtClass clazz, | public boolean makeReflective(CtClass clazz, | ||||
CtClass metaobject, CtClass metaclass) | CtClass metaobject, CtClass metaclass) | ||||
else | else | ||||
clazz.setAttribute("Reflective", new byte[0]); | clazz.setAttribute("Reflective", new byte[0]); | ||||
CtClass mlevel = classPool.get("javassist.reflect.Metalevel"); | |||||
CtClass mlevel = classPool.get("javassist.tools.reflect.Metalevel"); | |||||
boolean addMeta = !clazz.subtypeOf(mlevel); | boolean addMeta = !clazz.subtypeOf(mlevel); | ||||
if (addMeta) | if (addMeta) | ||||
clazz.addInterface(mlevel); | clazz.addInterface(mlevel); | ||||
CtField f; | CtField f; | ||||
if (addMeta) { | if (addMeta) { | ||||
f = new CtField(classPool.get("javassist.reflect.Metaobject"), | |||||
f = new CtField(classPool.get("javassist.tools.reflect.Metaobject"), | |||||
metaobjectField, clazz); | metaobjectField, clazz); | ||||
f.setModifiers(Modifier.PROTECTED); | f.setModifiers(Modifier.PROTECTED); | ||||
clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject)); | clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject)); | ||||
clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f)); | clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f)); | ||||
} | } | ||||
f = new CtField(classPool.get("javassist.reflect.ClassMetaobject"), | |||||
f = new CtField(classPool.get("javassist.tools.reflect.ClassMetaobject"), | |||||
classobjectField, clazz); | classobjectField, clazz); | ||||
f.setModifiers(Modifier.PRIVATE | Modifier.STATIC); | f.setModifiers(Modifier.PRIVATE | Modifier.STATIC); | ||||
clazz.addField(f, CtField.Initializer.byNew(metaclass, | clazz.addField(f, CtField.Initializer.byNew(metaclass, |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.reflect; | |||||
package javassist.tools.reflect; | |||||
/** | /** | ||||
* A template used for defining a reflective class. | * A template used for defining a reflective class. |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
import java.io.*; | import java.io.*; | ||||
import javassist.web.*; | |||||
import javassist.tools.web.*; | |||||
import javassist.CannotCompileException; | import javassist.CannotCompileException; | ||||
import javassist.NotFoundException; | import javassist.NotFoundException; | ||||
import javassist.ClassPool; | import javassist.ClassPool; | ||||
* If the classes of the exported objects are requested by the client-side | * If the classes of the exported objects are requested by the client-side | ||||
* JVM, this web server sends proxy classes for the requested classes. | * JVM, this web server sends proxy classes for the requested classes. | ||||
* | * | ||||
* @see javassist.rmi.ObjectImporter | |||||
* @see javassist.tools.rmi.ObjectImporter | |||||
*/ | */ | ||||
public class AppletServer extends Webserver { | public class AppletServer extends Webserver { | ||||
private StubGenerator stubGen; | private StubGenerator stubGen; | ||||
* @param obj the exported object. | * @param obj the exported object. | ||||
* @return the object identifier | * @return the object identifier | ||||
* | * | ||||
* @see javassist.rmi.ObjectImporter#lookupObject(String) | |||||
* @see javassist.tools.rmi.ObjectImporter#lookupObject(String) | |||||
*/ | */ | ||||
public synchronized int exportObject(String name, Object obj) | public synchronized int exportObject(String name, Object obj) | ||||
throws CannotCompileException | throws CannotCompileException |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
import java.io.*; | import java.io.*; | ||||
import java.net.*; | import java.net.*; | ||||
/** | /** | ||||
* The object importer enables applets to call a method on a remote | * The object importer enables applets to call a method on a remote | ||||
* object running on the <code>Webserver</code>. | |||||
* object running on the <code>Webserver</code> (the <b>main</b> class of this | |||||
* package). | |||||
* | * | ||||
* <p>To access the remote | * <p>To access the remote | ||||
* object, the applet first calls <code>lookupObject()</code> and | * object, the applet first calls <code>lookupObject()</code> and | ||||
* to catch the exception. However, good programs should catch | * to catch the exception. However, good programs should catch | ||||
* the <code>RuntimeException</code>. | * the <code>RuntimeException</code>. | ||||
* | * | ||||
* @see javassist.rmi.AppletServer | |||||
* @see javassist.rmi.RemoteException | |||||
* @see javassist.web.Viewer | |||||
* @see javassist.tools.rmi.AppletServer | |||||
* @see javassist.tools.rmi.RemoteException | |||||
* @see javassist.tools.web.Viewer | |||||
*/ | */ | ||||
public class ObjectImporter implements java.io.Serializable { | public class ObjectImporter implements java.io.Serializable { | ||||
private final byte[] endofline = { 0x0d, 0x0a }; | private final byte[] endofline = { 0x0d, 0x0a }; | ||||
/** | /** | ||||
* Constructs an object importer. | * Constructs an object importer. | ||||
* | * | ||||
* <p>If you run a program with <code>javassist.web.Viewer</code>, | |||||
* <p>If you run a program with <code>javassist.tools.web.Viewer</code>, | |||||
* you can construct an object importer as follows: | * you can construct an object importer as follows: | ||||
* | * | ||||
* <ul><pre> | * <ul><pre> | ||||
* ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort()); | * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort()); | ||||
* </pre></ul> | * </pre></ul> | ||||
* | * | ||||
* @see javassist.web.Viewer | |||||
* @see javassist.tools.web.Viewer | |||||
*/ | */ | ||||
public ObjectImporter(String servername, int port) { | public ObjectImporter(String servername, int port) { | ||||
this.orgServername = this.servername = servername; | this.orgServername = this.servername = servername; |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
public class ObjectNotFoundException extends Exception { | public class ObjectNotFoundException extends Exception { | ||||
public ObjectNotFoundException(String name) { | public ObjectNotFoundException(String name) { |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
/** | /** | ||||
* An interface implemented by proxy classes. | * An interface implemented by proxy classes. | ||||
* | * | ||||
* @see javassist.rmi.StubGenerator | |||||
* @see javassist.tools.rmi.StubGenerator | |||||
*/ | */ | ||||
public interface Proxy { | public interface Proxy { | ||||
int _getObjectId(); | int _getObjectId(); |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
/** | /** | ||||
* <code>RemoteException</code> represents any exception thrown | * <code>RemoteException</code> represents any exception thrown |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
/** | /** | ||||
* Remote reference. This class is internally used for sending a remote | * Remote reference. This class is internally used for sending a remote |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
/** | /** | ||||
* A template used for defining a proxy class. | * A template used for defining a proxy class. |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.rmi; | |||||
package javassist.tools.rmi; | |||||
import javassist.*; | import javassist.*; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
private static final String fieldImporter = "importer"; | private static final String fieldImporter = "importer"; | ||||
private static final String fieldObjectId = "objectId"; | private static final String fieldObjectId = "objectId"; | ||||
private static final String accessorObjectId = "_getObjectId"; | private static final String accessorObjectId = "_getObjectId"; | ||||
private static final String sampleClass = "javassist.rmi.Sample"; | |||||
private static final String sampleClass = "javassist.tools.rmi.Sample"; | |||||
private ClassPool classPool; | private ClassPool classPool; | ||||
private Hashtable proxyClasses; | private Hashtable proxyClasses; | ||||
forwardStaticMethod = c.getDeclaredMethod("forwardStatic"); | forwardStaticMethod = c.getDeclaredMethod("forwardStatic"); | ||||
proxyConstructorParamTypes | proxyConstructorParamTypes | ||||
= pool.get(new String[] { "javassist.rmi.ObjectImporter", | |||||
= pool.get(new String[] { "javassist.tools.rmi.ObjectImporter", | |||||
"int" }); | "int" }); | ||||
interfacesForProxy | interfacesForProxy | ||||
= pool.get(new String[] { "java.io.Serializable", | = pool.get(new String[] { "java.io.Serializable", | ||||
"javassist.rmi.Proxy" }); | |||||
"javassist.tools.rmi.Proxy" }); | |||||
exceptionForProxy | exceptionForProxy | ||||
= new CtClass[] { pool.get("javassist.rmi.RemoteException") }; | |||||
= new CtClass[] { pool.get("javassist.tools.rmi.RemoteException") }; | |||||
} | } | ||||
/** | /** | ||||
proxy.setInterfaces(interfacesForProxy); | proxy.setInterfaces(interfacesForProxy); | ||||
CtField f | CtField f | ||||
= new CtField(classPool.get("javassist.rmi.ObjectImporter"), | |||||
= new CtField(classPool.get("javassist.tools.rmi.ObjectImporter"), | |||||
fieldImporter, proxy); | fieldImporter, proxy); | ||||
f.setModifiers(Modifier.PRIVATE); | f.setModifiers(Modifier.PRIVATE); | ||||
proxy.addField(f, CtField.Initializer.byParameter(0)); | proxy.addField(f, CtField.Initializer.byParameter(0)); |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.web; | |||||
package javassist.tools.web; | |||||
/** | /** | ||||
* Thrown when receiving an invalid HTTP request. | * Thrown when receiving an invalid HTTP request. |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.web; | |||||
package javassist.tools.web; | |||||
import java.io.*; | import java.io.*; | ||||
import java.net.*; | import java.net.*; | ||||
* | * | ||||
* <p>To run, you should type: | * <p>To run, you should type: | ||||
* | * | ||||
* <ul><code>% java javassist.web.Viewer <i>host port</i> Main arg1, ...</code></ul> | |||||
* <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul> | |||||
* | * | ||||
* <p>This command calls <code>Main.main()</code> with <code>arg1,...</code> | * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code> | ||||
* All classes including <code>Main</code> are fetched from | * All classes including <code>Main</code> are fetched from | ||||
} | } | ||||
else | else | ||||
System.err.println( | System.err.println( | ||||
"Usage: java javassist.web.Viewer <host> <port> class [args ...]"); | |||||
"Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]"); | |||||
} | } | ||||
/** | /** | ||||
protected Class findClass(String name) throws ClassNotFoundException { | protected Class findClass(String name) throws ClassNotFoundException { | ||||
Class c = null; | Class c = null; | ||||
if (name.startsWith("java.") || name.startsWith("javax.") | if (name.startsWith("java.") || name.startsWith("javax.") | ||||
|| name.equals("javassist.web.Viewer")) | |||||
|| name.equals("javassist.tools.web.Viewer")) | |||||
c = findSystemClass(name); | c = findSystemClass(name); | ||||
if (c == null) | if (c == null) |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.web; | |||||
package javassist.tools.web; | |||||
import java.net.*; | import java.net.*; | ||||
import java.io.*; | import java.io.*; | ||||
} | } | ||||
else | else | ||||
System.err.println( | System.err.println( | ||||
"Usage: java javassist.web.Webserver <port number>"); | |||||
"Usage: java javassist.tools.web.Webserver <port number>"); | |||||
} | } | ||||
/** | /** |
* License. | * License. | ||||
*/ | */ | ||||
package javassist.tools; | |||||
package javassist.util; | |||||
import com.sun.jdi.*; | import com.sun.jdi.*; | ||||
import com.sun.jdi.connect.*; | import com.sun.jdi.connect.*; | ||||
private Trigger trigger; | private Trigger trigger; | ||||
private static final String HOST_NAME = "localhost"; | private static final String HOST_NAME = "localhost"; | ||||
private static final String TRIGGER_NAME = "javassist.tools.Trigger"; | |||||
private static final String TRIGGER_NAME = Trigger.class.getName(); | |||||
/** | /** | ||||
* Connects to the JVM. | * Connects to the JVM. |
<html> | |||||
<body> | |||||
Utility classes. | |||||
</body> | |||||
</html> |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
import java.io.BufferedOutputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.DataOutputStream; | |||||
import java.io.File; | |||||
import java.io.FileOutputStream; | |||||
import java.io.IOException; | |||||
import javassist.CannotCompileException; | |||||
import javassist.bytecode.ClassFile; | |||||
/** | |||||
* A helper class for implementing <code>ProxyFactory</code>. | |||||
* The users of <code>ProxyFactory</code> do not have to see this class. | |||||
* | |||||
* @see ProxyFactory | |||||
*/ | |||||
public class FactoryHelper { | |||||
/** | |||||
* Returns an index for accessing arrays in this class. | |||||
* | |||||
* @throws RuntimeException if a given type is not a primitive type. | |||||
*/ | |||||
public static final int typeIndex(Class type) { | |||||
Class[] list = primitiveTypes; | |||||
int n = list.length; | |||||
for (int i = 0; i < n; i++) | |||||
if (list[i] == type) | |||||
return i; | |||||
throw new RuntimeException("bad type:" + type.getName()); | |||||
} | |||||
/** | |||||
* <code>Class</code> objects representing primitive types. | |||||
*/ | |||||
public static final Class[] primitiveTypes = { | |||||
Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, | |||||
Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE | |||||
}; | |||||
/** | |||||
* The fully-qualified names of wrapper classes for primitive types. | |||||
*/ | |||||
public static final String[] wrapperTypes = { | |||||
"java.lang.Boolean", "java.lang.Byte", "java.lang.Character", | |||||
"java.lang.Short", "java.lang.Integer", "java.lang.Long", | |||||
"java.lang.Float", "java.lang.Double", "java.lang.Void" | |||||
}; | |||||
/** | |||||
* The descriptors of the constructors of wrapper classes. | |||||
*/ | |||||
public static final String[] wrapperDesc = { | |||||
"(Z)V", "(B)V", "(C)V", "(S)V", "(I)V", "(J)V", | |||||
"(F)V", "(D)V" | |||||
}; | |||||
/** | |||||
* The names of methods for obtaining a primitive value | |||||
* from a wrapper object. For example, <code>intValue()</code> | |||||
* is such a method for obtaining an integer value from a | |||||
* <code>java.lang.Integer</code> object. | |||||
*/ | |||||
public static final String[] unwarpMethods = { | |||||
"booleanValue", "byteValue", "charValue", "shortValue", | |||||
"intValue", "longValue", "floatValue", "doubleValue" | |||||
}; | |||||
/** | |||||
* The descriptors of the unwrapping methods contained | |||||
* in <code>unwrapMethods</code>. | |||||
*/ | |||||
public static final String[] unwrapDesc = { | |||||
"()Z", "()B", "()C", "()S", "()I", "()J", "()F", "()D" | |||||
}; | |||||
/** | |||||
* The data size of primitive types. <code>long</code> | |||||
* and <code>double</code> are 2; the others are 1. | |||||
*/ | |||||
public static final int[] dataSize = { | |||||
1, 1, 1, 1, 1, 2, 1, 2 | |||||
}; | |||||
/** | |||||
* Loads a class file by a given class loader. | |||||
*/ | |||||
public static Class toClass(ClassFile cf, ClassLoader loader) | |||||
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 }); | |||||
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; | |||||
} | |||||
catch (RuntimeException e) { | |||||
throw e; | |||||
} | |||||
catch (java.lang.reflect.InvocationTargetException e) { | |||||
throw new CannotCompileException(e.getTargetException()); | |||||
} | |||||
catch (Exception e) { | |||||
throw new CannotCompileException(e); | |||||
} | |||||
} | |||||
private static byte[] toBytecode(ClassFile cf) throws IOException { | |||||
ByteArrayOutputStream barray = new ByteArrayOutputStream(); | |||||
DataOutputStream out = new DataOutputStream(barray); | |||||
try { | |||||
cf.write(out); | |||||
} | |||||
finally { | |||||
out.close(); | |||||
} | |||||
return barray.toByteArray(); | |||||
} | |||||
/** | |||||
* Writes a class file. | |||||
*/ | |||||
public static void writeFile(ClassFile cf, String directoryName) | |||||
throws CannotCompileException { | |||||
try { | |||||
writeFile0(cf, directoryName); | |||||
} | |||||
catch (IOException e) { | |||||
throw new CannotCompileException(e); | |||||
} | |||||
} | |||||
private static void writeFile0(ClassFile cf, String directoryName) | |||||
throws CannotCompileException, IOException { | |||||
String classname = cf.getName(); | |||||
String filename = directoryName + File.separatorChar | |||||
+ classname.replace('.', File.separatorChar) + ".class"; | |||||
int pos = filename.lastIndexOf(File.separatorChar); | |||||
if (pos > 0) { | |||||
String dir = filename.substring(0, pos); | |||||
if (!dir.equals(".")) | |||||
new File(dir).mkdirs(); | |||||
} | |||||
DataOutputStream out = new DataOutputStream(new BufferedOutputStream( | |||||
new FileOutputStream(filename))); | |||||
try { | |||||
cf.write(out); | |||||
} | |||||
catch (IOException e) { | |||||
throw e; | |||||
} | |||||
finally { | |||||
out.close(); | |||||
} | |||||
} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
import java.lang.reflect.Method; | |||||
/** | |||||
* Selector of the methods implemented by a handler. | |||||
* | |||||
* @see ProxyFactory#setFilter(MethodFilter) | |||||
*/ | |||||
public interface MethodFilter { | |||||
/** | |||||
* Returns true if the given method is implemented by a handler. | |||||
*/ | |||||
boolean isHandled(Method m); | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
import java.lang.reflect.Method; | |||||
/** | |||||
* The interface implemented by the invocation handler of a proxy | |||||
* instance. | |||||
* | |||||
* @see ProxyFactory#setHandler(MethodHandler) | |||||
*/ | |||||
public interface MethodHandler { | |||||
/** | |||||
* Is called when a method is invoked on a proxy instance associated | |||||
* with this handler. This method must process that method invocation. | |||||
* | |||||
* @param self the proxy instance. | |||||
* @param thisMethod the overridden method declared in the super | |||||
* class or interface. | |||||
* @param proceed the forwarder method for invoking the overridden | |||||
* method. It is null if the overridden mehtod is | |||||
* abstract or declared in the interface. | |||||
* @param args an array of objects containing the values of | |||||
* the arguments passed in the method invocation | |||||
* on the proxy instance. If a parameter type is | |||||
* a primitive type, the type of the array element | |||||
* is a wrapper class. | |||||
* @return the resulting value of the method invocation. | |||||
* | |||||
* @throws Exception if the method invocation fails. | |||||
*/ | |||||
Object invoke(Object self, Method thisMethod, Method proceed, | |||||
Object[] args) throws Exception; | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
import java.lang.reflect.Field; | |||||
import java.lang.reflect.Method; | |||||
import java.lang.reflect.Constructor; | |||||
import java.lang.reflect.Member; | |||||
import java.lang.reflect.Modifier; | |||||
import java.util.HashMap; | |||||
import java.util.Iterator; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import javassist.CannotCompileException; | |||||
import javassist.bytecode.*; | |||||
/** | |||||
* Factory of dynamic proxy classes. | |||||
* | |||||
* <p>This factory generates a class that extends the given super class and implements | |||||
* the given interfaces. The calls of the methods inherited from the super class are | |||||
* forwarded and then <code>invoke()</code> is called on the method handler | |||||
* associated with the generated class. The calls of the methods from the interfaces | |||||
* are also forwarded to the method handler. | |||||
* | |||||
* <p>For example, if the following code is executed, | |||||
* | |||||
* <ul><pre> | |||||
* ProxyFactory f = new ProxyFactory(); | |||||
* f.setSuperclass(Foo.class); | |||||
* MethodHandler mi = new MethodHandler() { | |||||
* public Object invoke(Object self, Method m, Method proceed, | |||||
* Object[] args) throws Exception { | |||||
* System.out.println("Name: " + m.getName()); | |||||
* proceed.invoke(self, args); // execute the original method. | |||||
* } | |||||
* }; | |||||
* f.setHandler(mi); | |||||
* Class c = f.createClass(); | |||||
* Foo foo = (Foo)c.newInstance(); | |||||
* </pre></ul> | |||||
* | |||||
* <p>Then, the following method call will be forwarded to MethodHandler | |||||
* <code>mi</code> and prints a message before executing the originally called method | |||||
* <code>bar()</code> in <code>Foo</code>. | |||||
* | |||||
* <ul><pre> | |||||
* foo.bar(); | |||||
* </pre></ul> | |||||
* | |||||
* <p>To change the method handler during runtime, | |||||
* execute the following code: | |||||
* | |||||
* <ul><pre> | |||||
* MethodHandler mi2 = ... ; // another handler | |||||
* ((ProxyObject)foo).setHandler(mi2); | |||||
* </pre></ul> | |||||
* | |||||
* <p>Here is an example of method handler. It does not execute | |||||
* anything except invoking the original method: | |||||
* | |||||
* <ul><pre> | |||||
* class SimpleHandler implements MethodHandler { | |||||
* public Object invoke(Object self, Method m, | |||||
* Method proceed, Object[] args) throws Exception { | |||||
* return proceed.invoke(self, args); | |||||
* } | |||||
* } | |||||
* </pre></ul> | |||||
* | |||||
* @see MethodHandler | |||||
* @since 3.1 | |||||
*/ | |||||
public class ProxyFactory { | |||||
private Class superClass; | |||||
private Class[] interfaces; | |||||
private MethodFilter methodFilter; | |||||
private MethodHandler handler; | |||||
private Class thisClass; | |||||
/** | |||||
* If the value of this variable is not null, the class file of | |||||
* the generated proxy class is written under the directory specified | |||||
* by this variable. For example, if the value is | |||||
* <code>"."</code>, then the class file is written under the current | |||||
* directory. This method is for debugging. | |||||
* | |||||
* <p>The default value is null. | |||||
*/ | |||||
public String writeDirectory; | |||||
private static final Class OBJECT_TYPE = Object.class; | |||||
private static final String HOLDER = "_methods_"; | |||||
private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;"; | |||||
private static final String HANDLER = "handler"; | |||||
private static final String DEFAULT_INTERCEPTOR = "default_interceptor"; | |||||
private static final String HANDLER_TYPE | |||||
= 'L' + MethodHandler.class.getName().replace('.', '/') + ';'; | |||||
private static final String HANDLER_SETTER = "setHandler"; | |||||
private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V"; | |||||
/** | |||||
* Constructs a factory of proxy class. | |||||
*/ | |||||
public ProxyFactory() { | |||||
superClass = null; | |||||
interfaces = null; | |||||
methodFilter = null; | |||||
handler = new MethodHandler() { | |||||
public Object invoke(Object self, Method m, | |||||
Method proceed, Object[] args) | |||||
throws Exception | |||||
{ | |||||
return proceed.invoke(self, args); | |||||
} | |||||
}; | |||||
thisClass = null; | |||||
writeDirectory = null; | |||||
} | |||||
/** | |||||
* Sets the super class of a proxy class. | |||||
*/ | |||||
public void setSuperclass(Class clazz) { | |||||
superClass = clazz; | |||||
} | |||||
/** | |||||
* Sets the interfaces of a proxy class. | |||||
*/ | |||||
public void setInterfaces(Class[] ifs) { | |||||
interfaces = ifs; | |||||
} | |||||
/** | |||||
* Sets a filter that selects the methods that will be controlled by a handler. | |||||
*/ | |||||
public void setFilter(MethodFilter mf) { | |||||
methodFilter = mf; | |||||
} | |||||
/** | |||||
* Generates a proxy class. | |||||
*/ | |||||
public Class createClass() { | |||||
if (thisClass == null) | |||||
try { | |||||
ClassFile cf = make(); | |||||
ClassLoader cl = getClassLoader(); | |||||
if (writeDirectory != null) | |||||
FactoryHelper.writeFile(cf, writeDirectory); | |||||
thisClass = FactoryHelper.toClass(cf, cl); | |||||
setHandler(); | |||||
} | |||||
catch (CannotCompileException e) { | |||||
throw new RuntimeException(e.getMessage(), e); | |||||
} | |||||
return thisClass; | |||||
} | |||||
protected ClassLoader getClassLoader() { | |||||
if (superClass != null && !superClass.getName().equals("java.lang.Object")) | |||||
return superClass.getClassLoader(); | |||||
else if (interfaces != null && interfaces.length > 0) | |||||
return interfaces[0].getClassLoader(); | |||||
else | |||||
return this.getClass().getClassLoader(); | |||||
// return Thread.currentThread().getContextClassLoader(); | |||||
} | |||||
/** | |||||
* Sets the default invocation handler. This invocation handler is shared | |||||
* among all the instances of a proxy class unless another is explicitly | |||||
* specified. | |||||
*/ | |||||
public void setHandler(MethodHandler mi) { | |||||
handler = mi; | |||||
setHandler(); | |||||
} | |||||
private void setHandler() { | |||||
if (thisClass != null && handler != null) | |||||
try { | |||||
Field f = thisClass.getField(DEFAULT_INTERCEPTOR); | |||||
f.setAccessible(true); | |||||
f.set(null, handler); | |||||
f.setAccessible(false); | |||||
} | |||||
catch (Exception e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
private static int counter = 0; | |||||
private ClassFile make() throws CannotCompileException { | |||||
String superName, classname; | |||||
if (interfaces == null) | |||||
interfaces = new Class[0]; | |||||
if (superClass == null) { | |||||
superClass = OBJECT_TYPE; | |||||
superName = superClass.getName(); | |||||
classname = interfaces.length == 0 ? superName | |||||
: interfaces[0].getName(); | |||||
} | |||||
else { | |||||
superName = superClass.getName(); | |||||
classname = superName; | |||||
} | |||||
if (Modifier.isFinal(superClass.getModifiers())) | |||||
throw new CannotCompileException(superName + " is final"); | |||||
// generate a proxy name. | |||||
classname = classname + "_$$_javassist_" + counter++; | |||||
if (classname.startsWith("java.")) | |||||
classname = "org.javassist.tmp." + classname; | |||||
ClassFile cf = new ClassFile(false, classname, superName); | |||||
cf.setAccessFlags(AccessFlag.PUBLIC); | |||||
setInterfaces(cf, interfaces); | |||||
ConstPool pool = cf.getConstPool(); | |||||
FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE); | |||||
finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC); | |||||
cf.addField(finfo); | |||||
FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE); | |||||
finfo2.setAccessFlags(AccessFlag.PRIVATE); | |||||
cf.addField(finfo2); | |||||
HashMap allMethods = getMethods(superClass, interfaces); | |||||
int size = allMethods.size(); | |||||
makeConstructors(classname, cf, pool, classname); | |||||
int s = overrideMethods(cf, pool, classname, allMethods); | |||||
addMethodsHolder(cf, pool, classname, s); | |||||
addSetter(classname, cf, pool); | |||||
thisClass = null; | |||||
return cf; | |||||
} | |||||
private static void setInterfaces(ClassFile cf, Class[] interfaces) { | |||||
String setterIntf = ProxyObject.class.getName(); | |||||
String[] list; | |||||
if (interfaces == null || interfaces.length == 0) | |||||
list = new String[] { setterIntf }; | |||||
else { | |||||
list = new String[interfaces.length + 1]; | |||||
for (int i = 0; i < interfaces.length; i++) | |||||
list[i] = interfaces[i].getName(); | |||||
list[interfaces.length] = setterIntf; | |||||
} | |||||
cf.setInterfaces(list); | |||||
} | |||||
private static void addMethodsHolder(ClassFile cf, ConstPool cp, | |||||
String classname, int size) | |||||
throws CannotCompileException | |||||
{ | |||||
FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE); | |||||
finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC); | |||||
cf.addField(finfo); | |||||
MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V"); | |||||
Bytecode code = new Bytecode(cp, 0, 0); | |||||
code.addIconst(size * 2); | |||||
code.addAnewarray("java.lang.reflect.Method"); | |||||
code.addPutstatic(classname, HOLDER, HOLDER_TYPE); | |||||
code.addOpcode(Bytecode.RETURN); | |||||
minfo.setCodeAttribute(code.toCodeAttribute()); | |||||
cf.addMethod(minfo); | |||||
} | |||||
private static void addSetter(String classname, ClassFile cf, ConstPool cp) | |||||
throws CannotCompileException | |||||
{ | |||||
MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER, | |||||
HANDLER_SETTER_TYPE); | |||||
minfo.setAccessFlags(AccessFlag.PUBLIC); | |||||
Bytecode code = new Bytecode(cp, 2, 2); | |||||
code.addAload(0); | |||||
code.addAload(1); | |||||
code.addPutfield(classname, HANDLER, HANDLER_TYPE); | |||||
code.addOpcode(Bytecode.RETURN); | |||||
minfo.setCodeAttribute(code.toCodeAttribute()); | |||||
cf.addMethod(minfo); | |||||
} | |||||
private int overrideMethods(ClassFile cf, ConstPool cp, String className, | |||||
HashMap allMethods) | |||||
throws CannotCompileException | |||||
{ | |||||
String prefix = makeUniqueName("_d", allMethods); | |||||
Set entries = allMethods.entrySet(); | |||||
Iterator it = entries.iterator(); | |||||
int index = 0; | |||||
while (it.hasNext()) { | |||||
Map.Entry e = (Map.Entry)it.next(); | |||||
String key = (String)e.getKey(); | |||||
Method meth = (Method)e.getValue(); | |||||
int mod = meth.getModifiers(); | |||||
if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod) | |||||
&& isVisible(mod, className, meth)) | |||||
if (methodFilter == null || methodFilter.isHandled(meth)) | |||||
override(className, meth, prefix, index++, | |||||
keyToDesc(key), cf, cp); | |||||
} | |||||
return index; | |||||
} | |||||
private void override(String thisClassname, Method meth, String prefix, | |||||
int index, String desc, ClassFile cf, ConstPool cp) | |||||
throws CannotCompileException | |||||
{ | |||||
Class declClass = meth.getDeclaringClass(); | |||||
String delegatorName = prefix + index + meth.getName(); | |||||
if (Modifier.isAbstract(meth.getModifiers())) | |||||
delegatorName = null; | |||||
else { | |||||
MethodInfo delegator | |||||
= makeDelegator(meth, desc, cp, declClass, delegatorName); | |||||
cf.addMethod(delegator); | |||||
} | |||||
MethodInfo forwarder | |||||
= makeForwarder(thisClassname, meth, desc, cp, declClass, | |||||
delegatorName, index); | |||||
cf.addMethod(forwarder); | |||||
} | |||||
private void makeConstructors(String thisClassName, ClassFile cf, | |||||
ConstPool cp, String classname) throws CannotCompileException | |||||
{ | |||||
Constructor[] cons = superClass.getDeclaredConstructors(); | |||||
for (int i = 0; i < cons.length; i++) { | |||||
Constructor c = cons[i]; | |||||
int mod = c.getModifiers(); | |||||
if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod) | |||||
&& isVisible(mod, classname, c)) { | |||||
MethodInfo m = makeConstructor(thisClassName, c, cp, superClass); | |||||
cf.addMethod(m); | |||||
} | |||||
} | |||||
} | |||||
private static String makeUniqueName(String name, HashMap hash) { | |||||
Set keys = hash.keySet(); | |||||
if (makeUniqueName0(name, keys.iterator())) | |||||
return name; | |||||
for (int i = 100; i < 999; i++) { | |||||
String s = name + i; | |||||
if (makeUniqueName0(s, keys.iterator())) | |||||
return s; | |||||
} | |||||
throw new RuntimeException("cannot make a unique method name"); | |||||
} | |||||
private static boolean makeUniqueName0(String name, Iterator it) { | |||||
while (it.hasNext()) { | |||||
String key = (String)it.next(); | |||||
if (key.startsWith(name)) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Returns true if the method is visible from the class. | |||||
* | |||||
* @param mod the modifiers of the method. | |||||
*/ | |||||
private static boolean isVisible(int mod, String from, Member meth) { | |||||
if ((mod & Modifier.PRIVATE) != 0) | |||||
return false; | |||||
else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) | |||||
return true; | |||||
else { | |||||
String p = getPackageName(from); | |||||
String q = getPackageName(meth.getDeclaringClass().getName()); | |||||
if (p == null) | |||||
return q == null; | |||||
else | |||||
return p.equals(q); | |||||
} | |||||
} | |||||
private static String getPackageName(String name) { | |||||
int i = name.lastIndexOf('.'); | |||||
if (i < 0) | |||||
return null; | |||||
else | |||||
return name.substring(0, i); | |||||
} | |||||
private static HashMap getMethods(Class superClass, Class[] interfaceTypes) { | |||||
HashMap hash = new HashMap(); | |||||
for (int i = 0; i < interfaceTypes.length; i++) | |||||
getMethods(hash, interfaceTypes[i]); | |||||
getMethods(hash, superClass); | |||||
return hash; | |||||
} | |||||
private static void getMethods(HashMap hash, Class clazz) { | |||||
Class[] ifs = clazz.getInterfaces(); | |||||
for (int i = 0; i < ifs.length; i++) | |||||
getMethods(hash, ifs[i]); | |||||
Class parent = clazz.getSuperclass(); | |||||
if (parent != null) | |||||
getMethods(hash, parent); | |||||
Method[] methods = clazz.getDeclaredMethods(); | |||||
for (int i = 0; i < methods.length; i++) | |||||
if (!Modifier.isPrivate(methods[i].getModifiers())) { | |||||
Method m = methods[i]; | |||||
String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m); | |||||
hash.put(key, methods[i]); | |||||
} | |||||
} | |||||
private static String keyToDesc(String key) { | |||||
return key.substring(key.indexOf(':') + 1); | |||||
} | |||||
private static MethodInfo makeConstructor(String thisClassName, Constructor cons, | |||||
ConstPool cp, Class superClass) { | |||||
String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(), | |||||
Void.TYPE); | |||||
MethodInfo minfo = new MethodInfo(cp, "<init>", desc); | |||||
minfo.setAccessFlags(Modifier.PUBLIC); // cons.getModifiers() & ~Modifier.NATIVE | |||||
setThrows(minfo, cp, cons.getExceptionTypes()); | |||||
Bytecode code = new Bytecode(cp, 0, 0); | |||||
code.addAload(0); | |||||
code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE); | |||||
code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE); | |||||
code.addAload(0); | |||||
int s = addLoadParameters(code, cons.getParameterTypes(), 1); | |||||
code.addInvokespecial(superClass.getName(), "<init>", desc); | |||||
code.addOpcode(Opcode.RETURN); | |||||
code.setMaxLocals(++s); | |||||
minfo.setCodeAttribute(code.toCodeAttribute()); | |||||
return minfo; | |||||
} | |||||
private static MethodInfo makeDelegator(Method meth, String desc, | |||||
ConstPool cp, Class declClass, String delegatorName) { | |||||
MethodInfo delegator = new MethodInfo(cp, delegatorName, desc); | |||||
delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC | |||||
| (meth.getModifiers() & ~(Modifier.PRIVATE | |||||
| Modifier.PROTECTED | |||||
| Modifier.ABSTRACT | |||||
| Modifier.NATIVE | |||||
| Modifier.SYNCHRONIZED))); | |||||
setThrows(delegator, cp, meth); | |||||
Bytecode code = new Bytecode(cp, 0, 0); | |||||
code.addAload(0); | |||||
int s = addLoadParameters(code, meth.getParameterTypes(), 1); | |||||
code.addInvokespecial(declClass.getName(), meth.getName(), desc); | |||||
addReturn(code, meth.getReturnType()); | |||||
code.setMaxLocals(++s); | |||||
delegator.setCodeAttribute(code.toCodeAttribute()); | |||||
return delegator; | |||||
} | |||||
/** | |||||
* @param delegatorName null if the original method is abstract. | |||||
*/ | |||||
private static MethodInfo makeForwarder(String thisClassName, | |||||
Method meth, String desc, ConstPool cp, | |||||
Class declClass, String delegatorName, int index) { | |||||
MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc); | |||||
forwarder.setAccessFlags(Modifier.FINAL | |||||
| (meth.getModifiers() & ~(Modifier.ABSTRACT | |||||
| Modifier.NATIVE | |||||
| Modifier.SYNCHRONIZED))); | |||||
setThrows(forwarder, cp, meth); | |||||
int args = Descriptor.paramSize(desc); | |||||
Bytecode code = new Bytecode(cp, 0, args + 2); | |||||
/* | |||||
* if (methods[index * 2] == null) { | |||||
* methods[index * 2] | |||||
* = RuntimeSupport.findMethod(this, <overridden name>, <desc>); | |||||
* methods[index * 2 + 1] | |||||
* = RuntimeSupport.findMethod(this, <delegator name>, <desc>); | |||||
* or = null // the original method is abstract. | |||||
* } | |||||
* return ($r)handler.invoke(this, methods[index * 2], | |||||
* methods[index * 2 + 1], $args); | |||||
*/ | |||||
int origIndex = index * 2; | |||||
int delIndex = index * 2 + 1; | |||||
int arrayVar = args + 1; | |||||
code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE); | |||||
code.addAstore(arrayVar); | |||||
code.addAload(arrayVar); | |||||
code.addIconst(origIndex); | |||||
code.addOpcode(Opcode.AALOAD); | |||||
code.addOpcode(Opcode.IFNONNULL); | |||||
int pc = code.currentPc(); | |||||
code.addIndex(0); | |||||
callFindMethod(code, "findSuperMethod", arrayVar, origIndex, meth.getName(), desc); | |||||
callFindMethod(code, "findMethod", arrayVar, delIndex, delegatorName, desc); | |||||
code.write16bit(pc, code.currentPc() - pc + 1); | |||||
code.addAload(0); | |||||
code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE); | |||||
code.addAload(0); | |||||
code.addAload(arrayVar); | |||||
code.addIconst(origIndex); | |||||
code.addOpcode(Opcode.AALOAD); | |||||
code.addAload(arrayVar); | |||||
code.addIconst(delIndex); | |||||
code.addOpcode(Opcode.AALOAD); | |||||
makeParameterList(code, meth.getParameterTypes()); | |||||
code.addInvokeinterface(MethodHandler.class.getName(), "invoke", | |||||
"(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", | |||||
5); | |||||
Class retType = meth.getReturnType(); | |||||
addUnwrapper(code, retType); | |||||
addReturn(code, retType); | |||||
forwarder.setCodeAttribute(code.toCodeAttribute()); | |||||
return forwarder; | |||||
} | |||||
private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) { | |||||
Class[] exceptions = orig.getExceptionTypes(); | |||||
setThrows(minfo, cp, exceptions); | |||||
} | |||||
private static void setThrows(MethodInfo minfo, ConstPool cp, | |||||
Class[] exceptions) { | |||||
if (exceptions.length == 0) | |||||
return; | |||||
String[] list = new String[exceptions.length]; | |||||
for (int i = 0; i < exceptions.length; i++) | |||||
list[i] = exceptions[i].getName(); | |||||
ExceptionsAttribute ea = new ExceptionsAttribute(cp); | |||||
ea.setExceptions(list); | |||||
minfo.setExceptionsAttribute(ea); | |||||
} | |||||
private static int addLoadParameters(Bytecode code, Class[] params, | |||||
int offset) { | |||||
int stacksize = 0; | |||||
int n = params.length; | |||||
for (int i = 0; i < n; ++i) | |||||
stacksize += addLoad(code, stacksize + offset, params[i]); | |||||
return stacksize; | |||||
} | |||||
private static int addLoad(Bytecode code, int n, Class type) { | |||||
if (type.isPrimitive()) { | |||||
if (type == Long.TYPE) { | |||||
code.addLload(n); | |||||
return 2; | |||||
} | |||||
else if (type == Float.TYPE) | |||||
code.addFload(n); | |||||
else if (type == Double.TYPE) { | |||||
code.addDload(n); | |||||
return 2; | |||||
} | |||||
else | |||||
code.addIload(n); | |||||
} | |||||
else | |||||
code.addAload(n); | |||||
return 1; | |||||
} | |||||
private static int addReturn(Bytecode code, Class type) { | |||||
if (type.isPrimitive()) { | |||||
if (type == Long.TYPE) { | |||||
code.addOpcode(Opcode.LRETURN); | |||||
return 2; | |||||
} | |||||
else if (type == Float.TYPE) | |||||
code.addOpcode(Opcode.FRETURN); | |||||
else if (type == Double.TYPE) { | |||||
code.addOpcode(Opcode.DRETURN); | |||||
return 2; | |||||
} | |||||
else if (type == Void.TYPE) { | |||||
code.addOpcode(Opcode.RETURN); | |||||
return 0; | |||||
} | |||||
else | |||||
code.addOpcode(Opcode.IRETURN); | |||||
} | |||||
else | |||||
code.addOpcode(Opcode.ARETURN); | |||||
return 1; | |||||
} | |||||
private static void makeParameterList(Bytecode code, Class[] params) { | |||||
int regno = 1; | |||||
int n = params.length; | |||||
code.addIconst(n); | |||||
code.addAnewarray("java/lang/Object"); | |||||
for (int i = 0; i < n; i++) { | |||||
code.addOpcode(Opcode.DUP); | |||||
code.addIconst(i); | |||||
Class type = params[i]; | |||||
if (type.isPrimitive()) | |||||
regno = makeWrapper(code, type, regno); | |||||
else { | |||||
code.addAload(regno); | |||||
regno++; | |||||
} | |||||
code.addOpcode(Opcode.AASTORE); | |||||
} | |||||
} | |||||
private static int makeWrapper(Bytecode code, Class type, int regno) { | |||||
int index = FactoryHelper.typeIndex(type); | |||||
String wrapper = FactoryHelper.wrapperTypes[index]; | |||||
code.addNew(wrapper); | |||||
code.addOpcode(Opcode.DUP); | |||||
addLoad(code, regno, type); | |||||
code.addInvokespecial(wrapper, "<init>", | |||||
FactoryHelper.wrapperDesc[index]); | |||||
return regno + FactoryHelper.dataSize[index]; | |||||
} | |||||
/** | |||||
* @param methodName might be null. | |||||
*/ | |||||
private static void callFindMethod(Bytecode code, String findMethod, | |||||
int arrayVar, int index, String methodName, String desc) { | |||||
String findClass = RuntimeSupport.class.getName(); | |||||
String findDesc | |||||
= "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Method;"; | |||||
code.addAload(arrayVar); | |||||
code.addIconst(index); | |||||
if (methodName == null) | |||||
code.addOpcode(Opcode.ACONST_NULL); | |||||
else { | |||||
code.addAload(0); | |||||
code.addLdc(methodName); | |||||
code.addLdc(desc); | |||||
code.addInvokestatic(findClass, findMethod, findDesc); | |||||
} | |||||
code.addOpcode(Opcode.AASTORE); | |||||
} | |||||
private static void addUnwrapper(Bytecode code, Class type) { | |||||
if (type.isPrimitive()) { | |||||
if (type == Void.TYPE) | |||||
code.addOpcode(Opcode.POP); | |||||
else { | |||||
int index = FactoryHelper.typeIndex(type); | |||||
String wrapper = FactoryHelper.wrapperTypes[index]; | |||||
code.addCheckcast(wrapper); | |||||
code.addInvokevirtual(wrapper, | |||||
FactoryHelper.unwarpMethods[index], | |||||
FactoryHelper.unwrapDesc[index]); | |||||
} | |||||
} | |||||
else | |||||
code.addCheckcast(type.getName()); | |||||
} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
/** | |||||
* The interface implemented by proxy classes. | |||||
* | |||||
* @see ProxyFactory | |||||
*/ | |||||
public interface ProxyObject { | |||||
/** | |||||
* Sets a handler. It can be used for changing handlers | |||||
* during runtime. | |||||
*/ | |||||
void setHandler(MethodHandler mi); | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package javassist.util.proxy; | |||||
import java.lang.reflect.Method; | |||||
/** | |||||
* Runtime support routines that the classes generated by ProxyFactory use. | |||||
* | |||||
* @see ProxyFactory | |||||
*/ | |||||
public class RuntimeSupport { | |||||
/** | |||||
* Finds a method with the given name and descriptor. | |||||
* It searches only the class of self. | |||||
* | |||||
* @throws RuntimeException if the method is not found. | |||||
*/ | |||||
public static Method findMethod(Object self, String name, String desc) { | |||||
Method m = findMethod2(self.getClass(), name, desc); | |||||
if (m == null) | |||||
error(self, name, desc); | |||||
return m; | |||||
} | |||||
/** | |||||
* Finds a method that has the given name and descriptor and is declared | |||||
* in the super class. | |||||
* | |||||
* @throws RuntimeException if the method is not found. | |||||
*/ | |||||
public static Method findSuperMethod(Object self, String name, String desc) { | |||||
Class clazz = self.getClass(); | |||||
Method m = findSuperMethod2(clazz.getSuperclass(), name, desc); | |||||
if (m == null) | |||||
m = searchInterfaces(clazz, name, desc); | |||||
if (m == null) | |||||
error(self, name, desc); | |||||
return m; | |||||
} | |||||
private static void error(Object self, String name, String desc) { | |||||
throw new RuntimeException("not found " + name + ":" + desc | |||||
+ " in " + self.getClass().getName()); | |||||
} | |||||
private static Method findSuperMethod2(Class clazz, String name, String desc) { | |||||
Method m = findMethod2(clazz, name, desc); | |||||
if (m != null) | |||||
return m; | |||||
Class superClass = clazz.getSuperclass(); | |||||
if (superClass != null) { | |||||
m = findSuperMethod2(superClass, name, desc); | |||||
if (m != null) | |||||
return m; | |||||
} | |||||
return searchInterfaces(clazz, name, desc); | |||||
} | |||||
private static Method searchInterfaces(Class clazz, String name, String desc) { | |||||
Method m = null; | |||||
Class[] interfaces = clazz.getInterfaces(); | |||||
for (int i = 0; i < interfaces.length; i++) { | |||||
m = findSuperMethod2(interfaces[i], name, desc); | |||||
if (m != null) | |||||
return m; | |||||
} | |||||
return m; | |||||
} | |||||
private static Method findMethod2(Class clazz, String name, String desc) { | |||||
Method[] methods = clazz.getDeclaredMethods(); | |||||
int n = methods.length; | |||||
for (int i = 0; i < n; i++) | |||||
if (methods[i].getName().equals(name) | |||||
&& makeDescriptor(methods[i]).equals(desc)) | |||||
return methods[i]; | |||||
return null; | |||||
} | |||||
/** | |||||
* Makes a descriptor for a given method. | |||||
*/ | |||||
public static String makeDescriptor(Method m) { | |||||
Class[] params = m.getParameterTypes(); | |||||
return makeDescriptor(params, m.getReturnType()); | |||||
} | |||||
/** | |||||
* Makes a descriptor for a given method. | |||||
* | |||||
* @param params parameter types. | |||||
* @param retType return type. | |||||
*/ | |||||
public static String makeDescriptor(Class[] params, Class retType) { | |||||
StringBuffer sbuf = new StringBuffer(); | |||||
sbuf.append('('); | |||||
for (int i = 0; i < params.length; i++) | |||||
makeDesc(sbuf, params[i]); | |||||
sbuf.append(')'); | |||||
makeDesc(sbuf, retType); | |||||
return sbuf.toString(); | |||||
} | |||||
private static void makeDesc(StringBuffer sbuf, Class type) { | |||||
if (type.isArray()) { | |||||
sbuf.append('['); | |||||
makeDesc(sbuf, type.getComponentType()); | |||||
} | |||||
else if (type.isPrimitive()) { | |||||
if (type == Void.TYPE) | |||||
sbuf.append('V'); | |||||
else if (type == Integer.TYPE) | |||||
sbuf.append('I'); | |||||
else if (type == Byte.TYPE) | |||||
sbuf.append('B'); | |||||
else if (type == Long.TYPE) | |||||
sbuf.append('J'); | |||||
else if (type == Double.TYPE) | |||||
sbuf.append('D'); | |||||
else if (type == Float.TYPE) | |||||
sbuf.append('F'); | |||||
else if (type == Character.TYPE) | |||||
sbuf.append('C'); | |||||
else if (type == Short.TYPE) | |||||
sbuf.append('S'); | |||||
else if (type == Boolean.TYPE) | |||||
sbuf.append('Z'); | |||||
else | |||||
throw new RuntimeException("bad type: " + type.getName()); | |||||
} | |||||
else | |||||
sbuf.append('L').append(type.getName().replace('.', '/')) | |||||
.append(';'); | |||||
} | |||||
} |
<html> | |||||
<body> | |||||
Dynamic proxy (similar to <code>Enhancer</code> of <a href="http://cglib.sourceforge.net/">cglib</a>). | |||||
</body> | |||||
</html> |