diff options
author | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-01-11 06:06:30 +0000 |
---|---|---|
committer | chiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-01-11 06:06:30 +0000 |
commit | 52a455616e4077b5b61823cb4765c02fc6866f9a (patch) | |
tree | a9f95d54cccee9e336a667043b4e958d30257064 | |
parent | 5b8d2d6c7ab0102e8a1bb0384cf769ed8f0f34da (diff) | |
download | javassist-52a455616e4077b5b61823cb4765c02fc6866f9a.tar.gz javassist-52a455616e4077b5b61823cb4765c02fc6866f9a.zip |
restructred sub packages
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@233 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
55 files changed, 1303 insertions, 140 deletions
diff --git a/Readme.html b/Readme.html index 4699d715..9c88637d 100644 --- a/Readme.html +++ b/Readme.html @@ -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"/> diff --git a/sample/duplicate/DuplicatedObject.java b/sample/duplicate/DuplicatedObject.java index 5995abcc..7161493c 100644 --- a/sample/duplicate/DuplicatedObject.java +++ b/sample/duplicate/DuplicatedObject.java @@ -1,6 +1,6 @@ package sample.duplicate;
-import javassist.reflect.*;
+import javassist.tools.reflect.*;
public class DuplicatedObject extends Metaobject {
private DuplicatedObject backup;
diff --git a/sample/duplicate/Main.java b/sample/duplicate/Main.java index e152a23e..064f13cd 100644 --- a/sample/duplicate/Main.java +++ b/sample/duplicate/Main.java @@ -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);
}
}
diff --git a/sample/evolve/DemoServer.java b/sample/evolve/DemoServer.java index dd64c550..b334bccb 100644 --- a/sample/evolve/DemoServer.java +++ b/sample/evolve/DemoServer.java @@ -1,6 +1,6 @@ package sample.evolve;
-import javassist.web.*;
+import javassist.tools.web.*;
import java.io.*;
/**
diff --git a/sample/evolve/Evolution.java b/sample/evolve/Evolution.java index ecae0921..e804ff46 100644 --- a/sample/evolve/Evolution.java +++ b/sample/evolve/Evolution.java @@ -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);
diff --git a/sample/evolve/VersionManager.java b/sample/evolve/VersionManager.java index 184397fd..efecee19 100644 --- a/sample/evolve/VersionManager.java +++ b/sample/evolve/VersionManager.java @@ -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;
}
diff --git a/sample/hotswap/Test.java b/sample/hotswap/Test.java index e15afc9a..651d2184 100644 --- a/sample/hotswap/Test.java +++ b/sample/hotswap/Test.java @@ -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 { diff --git a/sample/reflect/Main.java b/sample/reflect/Main.java index d9733abc..972e8964 100644 --- a/sample/reflect/Main.java +++ b/sample/reflect/Main.java @@ -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);
}
diff --git a/sample/reflect/Person.java b/sample/reflect/Person.java index 445d3807..90ccb18f 100644 --- a/sample/reflect/Person.java +++ b/sample/reflect/Person.java @@ -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;
diff --git a/sample/reflect/VerboseMetaobj.java b/sample/reflect/VerboseMetaobj.java index 91dba579..cc47999c 100644 --- a/sample/reflect/VerboseMetaobj.java +++ b/sample/reflect/VerboseMetaobj.java @@ -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) {
diff --git a/sample/rmi/CountApplet.java b/sample/rmi/CountApplet.java index 0bebdaf9..e4ee0ee2 100644 --- a/sample/rmi/CountApplet.java +++ b/sample/rmi/CountApplet.java @@ -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;
diff --git a/sample/rmi/Counter.java b/sample/rmi/Counter.java index f8a0fcf5..0920ca73 100644 --- a/sample/rmi/Counter.java +++ b/sample/rmi/Counter.java @@ -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;
diff --git a/sample/rmi/start.html b/sample/rmi/start.html index 696b629c..33321ad1 100644 --- a/sample/rmi/start.html +++ b/sample/rmi/start.html @@ -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>
diff --git a/sample/rmi/webdemo.html b/sample/rmi/webdemo.html index d313ec3c..a2b595ce 100644 --- a/sample/rmi/webdemo.html +++ b/sample/rmi/webdemo.html @@ -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.
diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 74ab0d3e..d4178e7f 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -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) diff --git a/src/main/javassist/CtMethod.java b/src/main/javassist/CtMethod.java index 043c8d3b..abb42b88 100644 --- a/src/main/javassist/CtMethod.java +++ b/src/main/javassist/CtMethod.java @@ -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 diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java index a1f74c6d..b2a0ee23 100644 --- a/src/main/javassist/bytecode/Bytecode.java +++ b/src/main/javassist/bytecode/Bytecode.java @@ -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) { diff --git a/src/main/javassist/bytecode/Descriptor.java b/src/main/javassist/bytecode/Descriptor.java index ef194b7f..39577ce2 100644 --- a/src/main/javassist/bytecode/Descriptor.java +++ b/src/main/javassist/bytecode/Descriptor.java @@ -717,7 +717,6 @@ public class Descriptor { /** * Returns the first character of the current element. - * @return */ public char currentChar() { return desc.charAt(curPos); } diff --git a/src/main/javassist/bytecode/annotation/package.html b/src/main/javassist/bytecode/annotation/package.html index 6cf7e538..d0656db6 100644 --- a/src/main/javassist/bytecode/annotation/package.html +++ b/src/main/javassist/bytecode/annotation/package.html @@ -1,6 +1,6 @@ <html> <body> -Annotations API. +Bytecode-level Annotations API. <p>This package provides low-level API for editing annotations attributes. diff --git a/src/main/javassist/expr/MethodCall.java b/src/main/javassist/expr/MethodCall.java index 7bc2c388..9fd29e2a 100644 --- a/src/main/javassist/expr/MethodCall.java +++ b/src/main/javassist/expr/MethodCall.java @@ -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 */ diff --git a/src/main/javassist/tools/package.html b/src/main/javassist/tools/package.html index 1566e121..bee6208d 100644 --- a/src/main/javassist/tools/package.html +++ b/src/main/javassist/tools/package.html @@ -1,6 +1,6 @@ <html> <body> -Utility classes. +Covenient tools. </body> </html> diff --git a/src/main/javassist/reflect/CannotCreateException.java b/src/main/javassist/tools/reflect/CannotCreateException.java index a0933830..efa14111 100644 --- a/src/main/javassist/reflect/CannotCreateException.java +++ b/src/main/javassist/tools/reflect/CannotCreateException.java @@ -13,7 +13,7 @@ * License. */ -package javassist.reflect; +package javassist.tools.reflect; /** * Signals that <code>ClassMetaobject.newInstance()</code> fails. diff --git a/src/main/javassist/reflect/CannotInvokeException.java b/src/main/javassist/tools/reflect/CannotInvokeException.java index c778e89d..d283d6d7 100644 --- a/src/main/javassist/reflect/CannotInvokeException.java +++ b/src/main/javassist/tools/reflect/CannotInvokeException.java @@ -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 { diff --git a/src/main/javassist/reflect/CannotReflectException.java b/src/main/javassist/tools/reflect/CannotReflectException.java index 036ebf49..30c448b3 100644 --- a/src/main/javassist/reflect/CannotReflectException.java +++ b/src/main/javassist/tools/reflect/CannotReflectException.java @@ -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 { diff --git a/src/main/javassist/reflect/ClassMetaobject.java b/src/main/javassist/tools/reflect/ClassMetaobject.java index 61328452..d0a645cc 100644 --- a/src/main/javassist/reflect/ClassMetaobject.java +++ b/src/main/javassist/tools/reflect/ClassMetaobject.java @@ -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 { /** diff --git a/src/main/javassist/reflect/Compiler.java b/src/main/javassist/tools/reflect/Compiler.java index 734f598b..7e1fb943 100644 --- a/src/main/javassist/reflect/Compiler.java +++ b/src/main/javassist/tools/reflect/Compiler.java @@ -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>])+"); } } diff --git a/src/main/javassist/reflect/Loader.java b/src/main/javassist/tools/reflect/Loader.java index 76dce4d6..36189edf 100644 --- a/src/main/javassist/reflect/Loader.java +++ b/src/main/javassist/tools/reflect/Loader.java @@ -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) diff --git a/src/main/javassist/reflect/Metalevel.java b/src/main/javassist/tools/reflect/Metalevel.java index 8192267a..db45cad9 100644 --- a/src/main/javassist/reflect/Metalevel.java +++ b/src/main/javassist/tools/reflect/Metalevel.java @@ -13,7 +13,7 @@ * License. */ -package javassist.reflect; +package javassist.tools.reflect; /** * An interface to access a metaobject and a class metaobject. diff --git a/src/main/javassist/reflect/Metaobject.java b/src/main/javassist/tools/reflect/Metaobject.java index 8c3749aa..e89b5398 100644 --- a/src/main/javassist/reflect/Metaobject.java +++ b/src/main/javassist/tools/reflect/Metaobject.java @@ -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; diff --git a/src/main/javassist/reflect/Reflection.java b/src/main/javassist/tools/reflect/Reflection.java index cd4f441c..06ce2ccf 100644 --- a/src/main/javassist/reflect/Reflection.java +++ b/src/main/javassist/tools/reflect/Reflection.java @@ -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, diff --git a/src/main/javassist/reflect/Sample.java b/src/main/javassist/tools/reflect/Sample.java index 81bad691..4e70236a 100644 --- a/src/main/javassist/reflect/Sample.java +++ b/src/main/javassist/tools/reflect/Sample.java @@ -13,7 +13,7 @@ * License. */ -package javassist.reflect; +package javassist.tools.reflect; /** * A template used for defining a reflective class. diff --git a/src/main/javassist/reflect/package.html b/src/main/javassist/tools/reflect/package.html index 10a41964..10a41964 100644 --- a/src/main/javassist/reflect/package.html +++ b/src/main/javassist/tools/reflect/package.html diff --git a/src/main/javassist/rmi/AppletServer.java b/src/main/javassist/tools/rmi/AppletServer.java index 89cc92ab..5056e24c 100644 --- a/src/main/javassist/rmi/AppletServer.java +++ b/src/main/javassist/tools/rmi/AppletServer.java @@ -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 diff --git a/src/main/javassist/rmi/ObjectImporter.java b/src/main/javassist/tools/rmi/ObjectImporter.java index adad468d..75f5aa60 100644 --- a/src/main/javassist/rmi/ObjectImporter.java +++ b/src/main/javassist/tools/rmi/ObjectImporter.java @@ -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; diff --git a/src/main/javassist/rmi/ObjectNotFoundException.java b/src/main/javassist/tools/rmi/ObjectNotFoundException.java index 85bc316e..e54a3257 100644 --- a/src/main/javassist/rmi/ObjectNotFoundException.java +++ b/src/main/javassist/tools/rmi/ObjectNotFoundException.java @@ -13,7 +13,7 @@ * License. */ -package javassist.rmi; +package javassist.tools.rmi; public class ObjectNotFoundException extends Exception { public ObjectNotFoundException(String name) { diff --git a/src/main/javassist/rmi/Proxy.java b/src/main/javassist/tools/rmi/Proxy.java index f627ac63..1512b87f 100644 --- a/src/main/javassist/rmi/Proxy.java +++ b/src/main/javassist/tools/rmi/Proxy.java @@ -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(); diff --git a/src/main/javassist/rmi/RemoteException.java b/src/main/javassist/tools/rmi/RemoteException.java index ceb04f9f..27ebe71e 100644 --- a/src/main/javassist/rmi/RemoteException.java +++ b/src/main/javassist/tools/rmi/RemoteException.java @@ -13,7 +13,7 @@ * License. */ -package javassist.rmi; +package javassist.tools.rmi; /** * <code>RemoteException</code> represents any exception thrown diff --git a/src/main/javassist/rmi/RemoteRef.java b/src/main/javassist/tools/rmi/RemoteRef.java index fbd93add..edbf349f 100644 --- a/src/main/javassist/rmi/RemoteRef.java +++ b/src/main/javassist/tools/rmi/RemoteRef.java @@ -13,7 +13,7 @@ * License. */ -package javassist.rmi; +package javassist.tools.rmi; /** * Remote reference. This class is internally used for sending a remote diff --git a/src/main/javassist/rmi/Sample.java b/src/main/javassist/tools/rmi/Sample.java index b632cd03..a65b908d 100644 --- a/src/main/javassist/rmi/Sample.java +++ b/src/main/javassist/tools/rmi/Sample.java @@ -13,7 +13,7 @@ * License. */ -package javassist.rmi; +package javassist.tools.rmi; /** * A template used for defining a proxy class. diff --git a/src/main/javassist/rmi/StubGenerator.java b/src/main/javassist/tools/rmi/StubGenerator.java index eac40916..7681bd6d 100644 --- a/src/main/javassist/rmi/StubGenerator.java +++ b/src/main/javassist/tools/rmi/StubGenerator.java @@ -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)); diff --git a/src/main/javassist/rmi/package.html b/src/main/javassist/tools/rmi/package.html index 5432a948..5432a948 100644 --- a/src/main/javassist/rmi/package.html +++ b/src/main/javassist/tools/rmi/package.html diff --git a/src/main/javassist/web/BadHttpRequest.java b/src/main/javassist/tools/web/BadHttpRequest.java index a1aee86a..606ce997 100644 --- a/src/main/javassist/web/BadHttpRequest.java +++ b/src/main/javassist/tools/web/BadHttpRequest.java @@ -13,7 +13,7 @@ * License. */ -package javassist.web; +package javassist.tools.web; /** * Thrown when receiving an invalid HTTP request. diff --git a/src/main/javassist/web/Viewer.java b/src/main/javassist/tools/web/Viewer.java index debc52af..6e737406 100644 --- a/src/main/javassist/web/Viewer.java +++ b/src/main/javassist/tools/web/Viewer.java @@ -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) diff --git a/src/main/javassist/web/Webserver.java b/src/main/javassist/tools/web/Webserver.java index 4da031df..e580feca 100644 --- a/src/main/javassist/web/Webserver.java +++ b/src/main/javassist/tools/web/Webserver.java @@ -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>"); } /** diff --git a/src/main/javassist/web/package.html b/src/main/javassist/tools/web/package.html index 0c7fb453..0c7fb453 100644 --- a/src/main/javassist/web/package.html +++ b/src/main/javassist/tools/web/package.html diff --git a/src/main/javassist/tools/HotSwapper.java b/src/main/javassist/util/HotSwapper.java index 7b5b5fa2..07abe7a0 100644 --- a/src/main/javassist/tools/HotSwapper.java +++ b/src/main/javassist/util/HotSwapper.java @@ -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. diff --git a/src/main/javassist/util/package.html b/src/main/javassist/util/package.html new file mode 100644 index 00000000..349d9962 --- /dev/null +++ b/src/main/javassist/util/package.html @@ -0,0 +1,5 @@ +<html> +<body> +Utility classes. +</body> +</html> diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java new file mode 100644 index 00000000..01bd6bf1 --- /dev/null +++ b/src/main/javassist/util/proxy/FactoryHelper.java @@ -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(); + } + } +} diff --git a/src/main/javassist/util/proxy/MethodFilter.java b/src/main/javassist/util/proxy/MethodFilter.java new file mode 100644 index 00000000..67f9e409 --- /dev/null +++ b/src/main/javassist/util/proxy/MethodFilter.java @@ -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);
+}
diff --git a/src/main/javassist/util/proxy/MethodHandler.java b/src/main/javassist/util/proxy/MethodHandler.java new file mode 100644 index 00000000..7bd28ba0 --- /dev/null +++ b/src/main/javassist/util/proxy/MethodHandler.java @@ -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;
+}
diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java new file mode 100644 index 00000000..356c23bf --- /dev/null +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -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());
+ }
+}
diff --git a/src/main/javassist/util/proxy/ProxyObject.java b/src/main/javassist/util/proxy/ProxyObject.java new file mode 100644 index 00000000..4cba5c7b --- /dev/null +++ b/src/main/javassist/util/proxy/ProxyObject.java @@ -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); +} diff --git a/src/main/javassist/util/proxy/RuntimeSupport.java b/src/main/javassist/util/proxy/RuntimeSupport.java new file mode 100644 index 00000000..837ed6ca --- /dev/null +++ b/src/main/javassist/util/proxy/RuntimeSupport.java @@ -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(';');
+ }
+}
diff --git a/src/main/javassist/util/proxy/package.html b/src/main/javassist/util/proxy/package.html new file mode 100644 index 00000000..6c1354fa --- /dev/null +++ b/src/main/javassist/util/proxy/package.html @@ -0,0 +1,5 @@ +<html> +<body> +Dynamic proxy (similar to <code>Enhancer</code> of <a href="http://cglib.sourceforge.net/">cglib</a>). +</body> +</html> |