git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@233 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -137,7 +137,7 @@ set CLASSPATH=.;javassist.jar | |||
<ul><pre> | |||
% javac sample/reflect/*.java | |||
% java javassist.reflect.Loader sample.reflect.Main Joe | |||
% java javassist.tools.reflect.Loader sample.reflect.Main Joe | |||
</pre></ul> | |||
<p>Compare this result with that of the regular execution without reflection: | |||
@@ -151,7 +151,7 @@ set CLASSPATH=.;javassist.jar | |||
To do this, type the commands: | |||
<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> | |||
<p> Then, | |||
@@ -292,14 +292,18 @@ see javassist.Dump. | |||
<li>The return type of CtClass.stopPruning() was changed from void | |||
to boolean. | |||
<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> | |||
<p>- version 3.1 RC2 in September 7, 2005 |
@@ -109,18 +109,18 @@ to ${build.classes.dir}.</echo> | |||
excludepackagenames="javassist.compiler.*,javassist.convert.*" | |||
sourcepath="src/main" | |||
defaultexcludes="yes" | |||
locale="en_US" | |||
charset="iso-8859-1" | |||
destdir="html" | |||
author="true" | |||
version="true" | |||
use="true" | |||
Locale="en_US" | |||
charset="iso-8859-1" | |||
Public="true" | |||
public="true" | |||
nohelp="true" | |||
windowtitle="Javassist API"> | |||
<doctitle><![CDATA[<h1>Javassist</h1>]]></doctitle> | |||
<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> | |||
</target> | |||
@@ -151,7 +151,8 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||
<target name = "sample-all" | |||
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 name = "sample-test" depends="sample" > | |||
@@ -161,7 +162,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||
</target> | |||
<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"/> | |||
<arg line="sample.reflect.Main Joe" /> | |||
</java> | |||
@@ -212,6 +213,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||
<!-- for JDK 1.4 --> | |||
<target name = "sample-hotswap" depends="sample"> | |||
<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"> | |||
<jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000" /> | |||
<classpath refid="classpath"/> | |||
@@ -221,6 +223,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||
<!-- for Java 5 --> | |||
<target name = "sample-hotswap5" depends="sample"> | |||
<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"> | |||
<jvmarg line="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000" /> | |||
<classpath refid="classpath"/> |
@@ -1,6 +1,6 @@ | |||
package sample.duplicate; | |||
import javassist.reflect.*; | |||
import javassist.tools.reflect.*; | |||
public class DuplicatedObject extends Metaobject { | |||
private DuplicatedObject backup; |
@@ -3,7 +3,7 @@ package sample.duplicate; | |||
/* | |||
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. | |||
For example, you can implement fault tolerancy with this ability. One | |||
of the implementation techniques of fault tolernacy is to make a copy | |||
@@ -30,15 +30,15 @@ package sample.duplicate; | |||
% java sample.duplicate.Main | |||
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. | |||
*/ | |||
public class Main { | |||
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", | |||
"sample.duplicate.DuplicatedObject", | |||
"javassist.reflect.ClassMetaobject"); | |||
"javassist.tools.reflect.ClassMetaobject"); | |||
cl.run("sample.duplicate.Viewer", args); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
package sample.evolve; | |||
import javassist.web.*; | |||
import javassist.tools.web.*; | |||
import java.io.*; | |||
/** |
@@ -60,9 +60,9 @@ public class Evolution implements Translator { | |||
private void onLoadUpdatable(String classname) throws NotFoundException, | |||
CannotCompileException { | |||
// 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) | |||
return; | |||
@@ -72,7 +72,7 @@ public class Evolution implements Translator { | |||
int version; | |||
try { | |||
version = Integer.parseInt(classname.substring(i + 1)); | |||
version = Integer.parseInt(classname.substring(i + 2)); | |||
} | |||
catch (NumberFormatException e) { | |||
throw new NotFoundException(classname, e); |
@@ -41,7 +41,7 @@ public class VersionManager { | |||
else | |||
version = ((Integer)found).intValue() + 1; | |||
Class c = Class.forName(qualifiedClassname + '$' + version); | |||
Class c = Class.forName(qualifiedClassname + "$$" + version); | |||
versionNo.put(qualifiedClassname, new Integer(version)); | |||
return c; | |||
} |
@@ -1,5 +1,5 @@ | |||
import java.io.*; | |||
import javassist.tools.HotSwapper; | |||
import javassist.util.HotSwapper; | |||
public class Test { | |||
public static void main(String[] args) throws Exception { |
@@ -1,6 +1,6 @@ | |||
package sample.reflect; | |||
import javassist.reflect.Loader; | |||
import javassist.tools.reflect.Loader; | |||
/* | |||
The "verbose metaobject" example (JDK 1.2 or later only). | |||
@@ -14,7 +14,7 @@ import javassist.reflect.Loader; | |||
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: | |||
@@ -25,7 +25,7 @@ public class Main { | |||
Loader cl = (Loader)Main.class.getClassLoader(); | |||
cl.makeReflective("sample.reflect.Person", | |||
"sample.reflect.VerboseMetaobj", | |||
"javassist.reflect.ClassMetaobject"); | |||
"javassist.tools.reflect.ClassMetaobject"); | |||
cl.run("sample.reflect.Person", args); | |||
} |
@@ -4,8 +4,8 @@ | |||
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 String name; |
@@ -1,6 +1,6 @@ | |||
package sample.reflect; | |||
import javassist.reflect.*; | |||
import javassist.tools.reflect.*; | |||
public class VerboseMetaobj extends Metaobject { | |||
public VerboseMetaobj(Object self, Object[] args) { |
@@ -3,9 +3,9 @@ package sample.rmi; | |||
import java.applet.*; | |||
import java.awt.*; | |||
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 { | |||
private Font font; |
@@ -1,6 +1,6 @@ | |||
package sample.rmi; | |||
import javassist.rmi.AppletServer; | |||
import javassist.tools.rmi.AppletServer; | |||
import java.io.IOException; | |||
import javassist.CannotCompileException; | |||
import javassist.NotFoundException; |
@@ -12,4 +12,4 @@ Start! | |||
<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> |
@@ -6,7 +6,7 @@ | |||
local object. The applet can communicate through a socket with the | |||
host that executes the web server distributing that applet. However, | |||
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. | |||
The rules that the applet must be subject to are simpler than the | |||
standard Java RMI. | |||
@@ -36,7 +36,7 @@ Look at the lines shown with red: | |||
<p><b>Figure 1: Applet</b> | |||
<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 { | |||
private Font font; | |||
@@ -106,7 +106,7 @@ public class Counter { | |||
} | |||
</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, | |||
with which <code>Counter</code> must be an interface and it must be | |||
implemented by another class. | |||
@@ -167,7 +167,7 @@ following features: | |||
<p> With the Java RMI or Voyager, the applet programmer must define | |||
an interface for every remote object class and access the remote object | |||
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. | |||
It is suitable for writing simple distributed programs like applets. | |||
@@ -703,7 +703,7 @@ public abstract class CtClass { | |||
* | |||
* @param name method name | |||
* @param desc method descriptor | |||
* @see CtBehavior.getSignature() | |||
* @see CtBehavior#getSignature() | |||
* @see javassist.bytecode.Descriptor | |||
*/ | |||
public CtMethod getMethod(String name, String desc) |
@@ -118,7 +118,7 @@ public final class CtMethod extends CtBehavior { | |||
* | |||
* @param src the source text. | |||
* @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) | |||
throws CannotCompileException |
@@ -1339,7 +1339,7 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode { | |||
* Appends PUTSTATIC. | |||
* | |||
* @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. | |||
*/ | |||
public void addPutstatic(String classname, String fieldName, String desc) { |
@@ -717,7 +717,6 @@ public class Descriptor { | |||
/** | |||
* Returns the first character of the current element. | |||
* @return | |||
*/ | |||
public char currentChar() { return desc.charAt(curPos); } | |||
@@ -1,6 +1,6 @@ | |||
<html> | |||
<body> | |||
Annotations API. | |||
Bytecode-level Annotations API. | |||
<p>This package provides low-level API for editing annotations attributes. | |||
@@ -120,7 +120,7 @@ public class MethodCall extends Expr { | |||
* The method signature is represented by a character string | |||
* called method descriptor, which is defined in the JVM specification. | |||
* | |||
* @see javassist.CtBehavior.getSignature() | |||
* @see javassist.CtBehavior#getSignature() | |||
* @see javassist.bytecode.Descriptor | |||
* @since 3.1 | |||
*/ |
@@ -1,6 +1,6 @@ | |||
<html> | |||
<body> | |||
Utility classes. | |||
Covenient tools. | |||
</body> | |||
</html> |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
/** | |||
* Signals that <code>ClassMetaobject.newInstance()</code> fails. |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.IllegalAccessException; | |||
@@ -22,9 +22,9 @@ import java.lang.IllegalAccessException; | |||
* Thrown when method invocation using the reflection API has thrown | |||
* 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 { | |||
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import javassist.CannotCompileException; | |||
@@ -24,7 +24,7 @@ import javassist.CannotCompileException; | |||
* either ClassMetaobject or Metaobject. | |||
* | |||
* @author Brett Randall | |||
* @see javassist.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass) | |||
* @see javassist.tools.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass) | |||
* @see javassist.CannotCompileException | |||
*/ | |||
public class CannotReflectException extends CannotCompileException { |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import java.lang.reflect.*; | |||
import java.util.Arrays; | |||
@@ -35,8 +35,8 @@ import java.io.ObjectOutputStream; | |||
* <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass(); | |||
* </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 { | |||
/** |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import javassist.CtClass; | |||
import javassist.ClassPool; | |||
@@ -31,7 +31,7 @@ class CompiledClass { | |||
* <p>This translator directly modifies class files on a local disk so that | |||
* the classes represented by those class files are reflective. | |||
* 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. | |||
* | |||
* <p>The modified class files are given as the command-line parameters, | |||
@@ -63,9 +63,9 @@ class CompiledClass { | |||
* <p>Note that if the super class is also made reflective, it must be done | |||
* 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 { | |||
@@ -100,12 +100,12 @@ public class Compiler { | |||
String metaobj, classobj; | |||
if (entries[i].metaobject == null) | |||
metaobj = "javassist.reflect.Metaobject"; | |||
metaobj = "javassist.tools.reflect.Metaobject"; | |||
else | |||
metaobj = entries[i].metaobject; | |||
if (entries[i].classobject == null) | |||
classobj = "javassist.reflect.ClassMetaobject"; | |||
classobj = "javassist.tools.reflect.ClassMetaobject"; | |||
else | |||
classobj = entries[i].classobject; | |||
@@ -156,7 +156,7 @@ public class Compiler { | |||
} | |||
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>])+"); | |||
} | |||
} |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import javassist.CannotCompileException; | |||
import javassist.NotFoundException; | |||
@@ -29,10 +29,10 @@ import javassist.ClassPool; | |||
* <ul><pre> | |||
* public class Main { | |||
* 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", | |||
* "javassist.reflect.ClassMetaobject"); | |||
* "javassist.tools.reflect.ClassMetaobject"); | |||
* cl.run("MyApp", args); | |||
* } | |||
* } | |||
@@ -40,7 +40,7 @@ import javassist.ClassPool; | |||
* | |||
* <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>, ... | |||
* and <code>Main.main()</code> runs <code>MyApp.main()</code> with | |||
@@ -54,9 +54,9 @@ import javassist.ClassPool; | |||
* <ul><pre> | |||
* public class Main2 { | |||
* 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", | |||
* "javassist.reflect.ClassMetaobject"); | |||
* "javassist.tools.reflect.ClassMetaobject"); | |||
* cl.run("MyApp", args); | |||
* } | |||
* } | |||
@@ -67,11 +67,11 @@ import javassist.ClassPool; | |||
* <ul><pre>% java Main2 arg1, ...</pre></ul> | |||
* | |||
* <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 | |||
* to the same name space (security domain) as <code>MyApp</code> | |||
* 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, | |||
* see the notes in the manual page of <code>javassist.Loader</code>. | |||
* | |||
@@ -84,7 +84,7 @@ import javassist.ClassPool; | |||
* javassist.Loader cl | |||
* = new javassist.Loader(ClassPool.getDefault(reflection)); | |||
* reflection.makeReflective("Person", "MyMetaobject", | |||
* "javassist.reflect.ClassMetaobject"); | |||
* "javassist.tools.reflect.ClassMetaobject"); | |||
* cl.run("MyApp", args); | |||
* } | |||
* } | |||
@@ -92,18 +92,18 @@ import javassist.ClassPool; | |||
* | |||
* <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 | |||
* <code>javax.*</code> pacakge because of the specifications | |||
* on the class loading algorithm of Java. The JVM does not allow to | |||
* load such a system class with a user class loader. | |||
* | |||
* <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. | |||
* | |||
* @see javassist.reflect.Reflection | |||
* @see javassist.reflect.Compiler | |||
* @see javassist.tools.reflect.Reflection | |||
* @see javassist.tools.reflect.Compiler | |||
* @see javassist.Loader | |||
*/ | |||
public class Loader extends javassist.Loader { | |||
@@ -130,7 +130,7 @@ public class Loader extends javassist.Loader { | |||
*/ | |||
public Loader() throws CannotCompileException, NotFoundException { | |||
super(); | |||
delegateLoadingOf("javassist.reflect.Loader"); | |||
delegateLoadingOf("javassist.tools.reflect.Loader"); | |||
reflection = new Reflection(); | |||
ClassPool pool = ClassPool.getDefault(); | |||
@@ -151,8 +151,8 @@ public class Loader extends javassist.Loader { | |||
* <code>ClassMetaobject</code>. | |||
* @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, | |||
String metaobject, String metaclass) |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
/** | |||
* An interface to access a metaobject and a class metaobject. |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import java.lang.reflect.Method; | |||
import java.io.Serializable; | |||
@@ -39,8 +39,8 @@ import java.io.ObjectOutputStream; | |||
* <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject(); | |||
* </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 { | |||
protected ClassMetaobject classmetaobject; | |||
@@ -88,7 +88,7 @@ public class Metaobject implements Serializable { | |||
/** | |||
* Obtains the class metaobject associated with this metaobject. | |||
* | |||
* @see javassist.reflect.ClassMetaobject | |||
* @see javassist.tools.reflect.ClassMetaobject | |||
*/ | |||
public final ClassMetaobject getClassMetaobject() { | |||
return classmetaobject; |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
import javassist.*; | |||
import javassist.CtMethod.ConstParameter; | |||
@@ -54,10 +54,10 @@ import javassist.CtMethod.ConstParameter; | |||
* } | |||
* </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 { | |||
@@ -69,9 +69,9 @@ public class Reflection implements Translator { | |||
static final String readPrefix = "_r_"; | |||
static final String writePrefix = "_w_"; | |||
static final String metaobjectClassName = "javassist.reflect.Metaobject"; | |||
static final String metaobjectClassName = "javassist.tools.reflect.Metaobject"; | |||
static final String classMetaobjectClassName | |||
= "javassist.reflect.ClassMetaobject"; | |||
= "javassist.tools.reflect.ClassMetaobject"; | |||
protected CtMethod trapMethod, trapStaticMethod; | |||
protected CtMethod trapRead, trapWrite; | |||
@@ -103,9 +103,9 @@ public class Reflection implements Translator { | |||
public void start(ClassPool pool) throws NotFoundException { | |||
classPool = pool; | |||
final String msg | |||
= "javassist.reflect.Sample is not found or broken."; | |||
= "javassist.tools.reflect.Sample is not found or broken."; | |||
try { | |||
CtClass c = classPool.get("javassist.reflect.Sample"); | |||
CtClass c = classPool.get("javassist.tools.reflect.Sample"); | |||
trapMethod = c.getDeclaredMethod("trap"); | |||
trapStaticMethod = c.getDeclaredMethod("trapStatic"); | |||
trapRead = c.getDeclaredMethod("trapRead"); | |||
@@ -139,8 +139,8 @@ public class Reflection implements Translator { | |||
* @param metaclass the class name of the class metaobject. | |||
* @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, | |||
String metaobject, String metaclass) | |||
@@ -165,8 +165,8 @@ public class Reflection implements Translator { | |||
* <code>ClassMetaobject</code>. | |||
* @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, | |||
Class metaobject, Class metaclass) | |||
@@ -191,8 +191,8 @@ public class Reflection implements Translator { | |||
* <code>ClassMetaobject</code>. | |||
* @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, | |||
CtClass metaobject, CtClass metaclass) | |||
@@ -243,7 +243,7 @@ public class Reflection implements Translator { | |||
else | |||
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); | |||
if (addMeta) | |||
clazz.addInterface(mlevel); | |||
@@ -253,7 +253,7 @@ public class Reflection implements Translator { | |||
CtField f; | |||
if (addMeta) { | |||
f = new CtField(classPool.get("javassist.reflect.Metaobject"), | |||
f = new CtField(classPool.get("javassist.tools.reflect.Metaobject"), | |||
metaobjectField, clazz); | |||
f.setModifiers(Modifier.PROTECTED); | |||
clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject)); | |||
@@ -262,7 +262,7 @@ public class Reflection implements Translator { | |||
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); | |||
f.setModifiers(Modifier.PRIVATE | Modifier.STATIC); | |||
clazz.addField(f, CtField.Initializer.byNew(metaclass, |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.reflect; | |||
package javassist.tools.reflect; | |||
/** | |||
* A template used for defining a reflective class. |
@@ -13,10 +13,11 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
import java.io.*; | |||
import javassist.web.*; | |||
import javassist.tools.web.*; | |||
import javassist.CannotCompileException; | |||
import javassist.NotFoundException; | |||
import javassist.ClassPool; | |||
@@ -31,7 +32,7 @@ import java.util.Vector; | |||
* If the classes of the exported objects are requested by the client-side | |||
* 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 { | |||
private StubGenerator stubGen; | |||
@@ -102,7 +103,7 @@ public class AppletServer extends Webserver { | |||
* @param obj the exported object. | |||
* @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) | |||
throws CannotCompileException |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
import java.io.*; | |||
import java.net.*; | |||
@@ -22,7 +22,8 @@ import java.lang.reflect.*; | |||
/** | |||
* 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 | |||
* object, the applet first calls <code>lookupObject()</code> and | |||
@@ -66,9 +67,9 @@ import java.lang.reflect.*; | |||
* to catch the exception. However, good programs should catch | |||
* 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 { | |||
private final byte[] endofline = { 0x0d, 0x0a }; | |||
@@ -95,7 +96,7 @@ public class ObjectImporter implements java.io.Serializable { | |||
/** | |||
* 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: | |||
* | |||
* <ul><pre> | |||
@@ -103,7 +104,7 @@ public class ObjectImporter implements java.io.Serializable { | |||
* ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort()); | |||
* </pre></ul> | |||
* | |||
* @see javassist.web.Viewer | |||
* @see javassist.tools.web.Viewer | |||
*/ | |||
public ObjectImporter(String servername, int port) { | |||
this.orgServername = this.servername = servername; |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
public class ObjectNotFoundException extends Exception { | |||
public ObjectNotFoundException(String name) { |
@@ -13,12 +13,12 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
/** | |||
* An interface implemented by proxy classes. | |||
* | |||
* @see javassist.rmi.StubGenerator | |||
* @see javassist.tools.rmi.StubGenerator | |||
*/ | |||
public interface Proxy { | |||
int _getObjectId(); |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
/** | |||
* <code>RemoteException</code> represents any exception thrown |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
/** | |||
* Remote reference. This class is internally used for sending a remote |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
/** | |||
* A template used for defining a proxy class. |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.rmi; | |||
package javassist.tools.rmi; | |||
import javassist.*; | |||
import java.lang.reflect.Method; | |||
@@ -43,7 +43,7 @@ public class StubGenerator implements Translator { | |||
private static final String fieldImporter = "importer"; | |||
private static final String fieldObjectId = "objectId"; | |||
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 Hashtable proxyClasses; | |||
@@ -74,13 +74,13 @@ public class StubGenerator implements Translator { | |||
forwardStaticMethod = c.getDeclaredMethod("forwardStatic"); | |||
proxyConstructorParamTypes | |||
= pool.get(new String[] { "javassist.rmi.ObjectImporter", | |||
= pool.get(new String[] { "javassist.tools.rmi.ObjectImporter", | |||
"int" }); | |||
interfacesForProxy | |||
= pool.get(new String[] { "java.io.Serializable", | |||
"javassist.rmi.Proxy" }); | |||
"javassist.tools.rmi.Proxy" }); | |||
exceptionForProxy | |||
= new CtClass[] { pool.get("javassist.rmi.RemoteException") }; | |||
= new CtClass[] { pool.get("javassist.tools.rmi.RemoteException") }; | |||
} | |||
/** | |||
@@ -139,7 +139,7 @@ public class StubGenerator implements Translator { | |||
proxy.setInterfaces(interfacesForProxy); | |||
CtField f | |||
= new CtField(classPool.get("javassist.rmi.ObjectImporter"), | |||
= new CtField(classPool.get("javassist.tools.rmi.ObjectImporter"), | |||
fieldImporter, proxy); | |||
f.setModifiers(Modifier.PRIVATE); | |||
proxy.addField(f, CtField.Initializer.byParameter(0)); |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.web; | |||
package javassist.tools.web; | |||
/** | |||
* Thrown when receiving an invalid HTTP request. |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.web; | |||
package javassist.tools.web; | |||
import java.io.*; | |||
import java.net.*; | |||
@@ -27,7 +27,7 @@ import java.net.*; | |||
* | |||
* <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> | |||
* All classes including <code>Main</code> are fetched from | |||
@@ -63,7 +63,7 @@ public class Viewer extends ClassLoader { | |||
} | |||
else | |||
System.err.println( | |||
"Usage: java javassist.web.Viewer <host> <port> class [args ...]"); | |||
"Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]"); | |||
} | |||
/** | |||
@@ -138,7 +138,7 @@ public class Viewer extends ClassLoader { | |||
protected Class findClass(String name) throws ClassNotFoundException { | |||
Class c = null; | |||
if (name.startsWith("java.") || name.startsWith("javax.") | |||
|| name.equals("javassist.web.Viewer")) | |||
|| name.equals("javassist.tools.web.Viewer")) | |||
c = findSystemClass(name); | |||
if (c == null) |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.web; | |||
package javassist.tools.web; | |||
import java.net.*; | |||
import java.io.*; | |||
@@ -82,7 +82,7 @@ public class Webserver { | |||
} | |||
else | |||
System.err.println( | |||
"Usage: java javassist.web.Webserver <port number>"); | |||
"Usage: java javassist.tools.web.Webserver <port number>"); | |||
} | |||
/** |
@@ -13,7 +13,7 @@ | |||
* License. | |||
*/ | |||
package javassist.tools; | |||
package javassist.util; | |||
import com.sun.jdi.*; | |||
import com.sun.jdi.connect.*; | |||
@@ -81,7 +81,7 @@ public class HotSwapper { | |||
private Trigger trigger; | |||
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. |
@@ -0,0 +1,5 @@ | |||
<html> | |||
<body> | |||
Utility classes. | |||
</body> | |||
</html> |
@@ -0,0 +1,182 @@ | |||
/* | |||
* 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(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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; | |||
} |
@@ -0,0 +1,699 @@ | |||
/* | |||
* 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()); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,157 @@ | |||
/* | |||
* 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(';'); | |||
} | |||
} |
@@ -0,0 +1,5 @@ | |||
<html> | |||
<body> | |||
Dynamic proxy (similar to <code>Enhancer</code> of <a href="http://cglib.sourceforge.net/">cglib</a>). | |||
</body> | |||
</html> |