git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@76 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -67,7 +67,12 @@ other editors. | |||
<h2>How to run sample programs</h2> | |||
<p>JDK 1.2.2 or later is needed. | |||
<p>JDK 1.3 or later is needed. | |||
<h3>0. If you have Apache Ant</h3> | |||
<p>Run the sample-all task. | |||
Otherwise, follow the instructions below. | |||
<h3>1. Move to the directory where this Readme.html file is located.</h3> | |||
@@ -253,6 +258,8 @@ see javassist.Dump. | |||
<p>- version 2.7 | |||
<ul> | |||
<li>javassist.bytecode.annotation has been added. | |||
<li>Now local variables were made available in the source text passed to | |||
CtBehavior.insertBefore(), MethodCall.replace(), etc. | |||
<li>CtClass.main(), which prints the version number, has been added. |
@@ -1,18 +1,21 @@ | |||
<?xml version="1.0"?> | |||
<!-- ======================================================================= --> | |||
<!-- JBoss build file --> | |||
<!-- ======================================================================= --> | |||
<!-- =================================================================== --> | |||
<!-- JBoss build file --> | |||
<!-- =================================================================== --> | |||
<project name="javassist" default="jar" basedir="."> | |||
<property name="dist-version" value="javassist-2.7"/> | |||
<property environment="env"/> | |||
<property name="target.jar" value="javassist.jar"/> | |||
<property name="src.dir" value="${basedir}/src/main"/> | |||
<property name="build.dir" value="${basedir}/build"/> | |||
<property name="build.classes.dir" value="${build.dir}/classes"/> | |||
<property name="run.dir" value="${build.classes.dir}"/> | |||
<!-- Build classpath --> | |||
<path id="classpath"> | |||
<pathelement location="${build.classes.dir}"/> | |||
@@ -61,7 +64,7 @@ to ${build.classes.dir}.</echo> | |||
</target> | |||
<target name="jar" depends="compile"> | |||
<jar jarfile="javassist.jar" manifest="${src.dir}/META-INF/MANIFEST.MF"> | |||
<jar jarfile="${target.jar}" manifest="${src.dir}/META-INF/MANIFEST.MF"> | |||
<fileset dir="${build.classes.dir}"> | |||
<include name="**/*.class"/> | |||
</fileset> | |||
@@ -103,8 +106,72 @@ Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.</i>]]></bottom> | |||
<target name="clean"> | |||
<delete dir="build"/> | |||
<delete dir="html"/> | |||
<delete file="javassist.jar"/> | |||
<delete file="${target.jar}"/> | |||
<delete file="${dist-version}.zip"/> | |||
</target> | |||
</project> | |||
<!-- =================================================================== --> | |||
<!-- Run samples --> | |||
<!-- =================================================================== --> | |||
<target name = "sample-all" | |||
depends="sample-test,sample-reflect,sample-duplicate,sample-vector"> | |||
<echo>** please run sample-rmi and sample-evolve separately **</echo> | |||
</target> | |||
<target name = "sample-test" depends="sample" > | |||
<java fork="true" dir="${run.dir}" classname="sample.Test"> | |||
<classpath refid="classpath"/> | |||
</java> | |||
</target> | |||
<target name = "sample-reflect" depends="sample" > | |||
<java fork="true" dir="${run.dir}" classname="javassist.reflect.Loader"> | |||
<classpath refid="classpath"/> | |||
<arg line="sample.reflect.Main Joe" /> | |||
</java> | |||
</target> | |||
<target name = "sample-duplicate" depends="sample" > | |||
<echo>run sample.duplicate.Viewer without reflection</echo> | |||
<java fork="true" dir="${run.dir}" classname="sample.duplicate.Viewer"> | |||
<classpath refid="classpath"/> | |||
</java> | |||
<echo>run sample.duplicate.Viewer with reflection</echo> | |||
<java fork="true" dir="${run.dir}" classname="sample.duplicate.Main"> | |||
<classpath refid="classpath"/> | |||
</java> | |||
</target> | |||
<target name = "sample-vector" depends="sample" > | |||
<echo>javassist.preproc.Compiler sample/vector/Test.j</echo> | |||
<java fork="true" dir="${run.dir}" classname="javassist.preproc.Compiler"> | |||
<classpath refid="classpath"/> | |||
<arg line="sample/vector/Test.j"/> | |||
</java> | |||
<echo>javac sample/vector/Test.java</echo> | |||
<javac srcdir="${build.classes.dir}" | |||
destdir="${build.classes.dir}" | |||
includes="sample/vector/Test.java"> | |||
<classpath refid="classpath"/> | |||
</javac> | |||
<java fork="true" dir="${run.dir}" classname="sample.vector.Test" /> | |||
</target> | |||
<target name = "sample-rmi" depends="sample" > | |||
<echo>** Please open sample/rmi/webdemo.html with your browser **</echo> | |||
<java fork="true" dir="${run.dir}" classname="sample.rmi.Counter"> | |||
<classpath refid="classpath"/> | |||
<arg value="5001" /> | |||
</java> | |||
</target> | |||
<target name = "sample-evolve" depends="sample" > | |||
<echo>** Please open http://localhost:5003/demo.html with your browser **</echo> | |||
<java fork="true" dir="${run.dir}" classname="sample.evolve.DemoLoader"> | |||
<classpath refid="classpath"/> | |||
<arg value="5003" /> | |||
</java> | |||
</target> | |||
</project> |
@@ -23,7 +23,7 @@ public class Test { | |||
} | |||
public static void main(String[] args) throws Exception { | |||
ClassPool pool = ClassPool.getDefault(null); | |||
ClassPool pool = ClassPool.getDefault(); | |||
CtClass cc = pool.get("sample.Test"); | |||
try { |
@@ -29,12 +29,13 @@ public class DemoLoader { | |||
* updatable. Then it runs main() in sample.evolve.DemoServer. | |||
*/ | |||
public static void main(String[] args) throws Throwable { | |||
Evolution translator = new Evolution(); | |||
ClassPool cp = ClassPool.getDefault(translator); | |||
Loader cl = new Loader(); | |||
cl.setClassPool(cp); | |||
Evolution translator = new Evolution(); | |||
ClassPool cp = ClassPool.getDefault(); | |||
cp.insertTranslator(translator); | |||
Loader cl = new Loader(); | |||
cl.setClassPool(cp); | |||
translator.makeUpdatable("sample.evolve.WebPage"); | |||
cl.run("sample.evolve.DemoServer", args); | |||
translator.makeUpdatable("sample.evolve.WebPage"); | |||
cl.run("sample.evolve.DemoServer", args); | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 1999-2004 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; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
/** | |||
* Abstract root of ClassPool and ClassPoolTail. | |||
*/ | |||
abstract class AbsClassPool { | |||
public abstract String toString(); | |||
public abstract void recordInvalidClassName(String name); | |||
abstract byte[] readSource(String classname) | |||
throws NotFoundException, IOException, CannotCompileException; | |||
abstract boolean write0(String classname, DataOutputStream out, | |||
boolean callback) | |||
throws NotFoundException, CannotCompileException, IOException; | |||
abstract URL find(String classname); | |||
public abstract ClassPath appendSystemPath(); | |||
public abstract ClassPath insertClassPath(ClassPath cp); | |||
public abstract ClassPath appendClassPath(ClassPath cp); | |||
public abstract ClassPath insertClassPath(String pathname) | |||
throws NotFoundException; | |||
public abstract ClassPath appendClassPath(String pathname) | |||
throws NotFoundException; | |||
public abstract void removeClassPath(ClassPath cp); | |||
} |
@@ -39,7 +39,7 @@ public interface ClassPath { | |||
* <p>This method can return null if the specified class file is not | |||
* found. If null is returned, the next search path is examined. | |||
* However, if an error happens, this method must throw an exception | |||
* so that the search is terminated. | |||
* so that the search will be terminated. | |||
* | |||
* <p>This method should not modify the contents of the class file. | |||
* Use <code>javassist.Translator</code> for modification. |
@@ -85,87 +85,63 @@ import java.util.Hashtable; | |||
* @see javassist.ClassPath | |||
* @see javassist.Translator | |||
*/ | |||
public class ClassPool { | |||
/* If this field is null, then the object must be an instance of | |||
* ClassPoolTail. | |||
*/ | |||
protected ClassPool source; | |||
public class ClassPool extends AbsClassPool { | |||
protected AbsClassPool source; | |||
protected ClassPool parent; | |||
protected Translator translator; | |||
protected Hashtable classes; // should be synchronous | |||
/** | |||
* Provide a hook so that subclasses can do their own | |||
* caching of classes | |||
* | |||
* @see #removeCached(String) | |||
*/ | |||
protected CtClass getCached(String classname) | |||
{ | |||
return (CtClass)classes.get(classname); | |||
} | |||
/** | |||
* Provide a hook so that subclasses can do their own | |||
* caching of classes | |||
* | |||
* @see #getCached(String) | |||
*/ | |||
protected void removeCached(String classname) | |||
{ | |||
classes.remove(classname); | |||
} | |||
/** | |||
* Creates a class pool. | |||
* | |||
* @param src the source of class files. If it is null, | |||
* the class search path is initially null. | |||
* @see javassist.ClassPool#getDefault() | |||
* Table of registered cflow variables. | |||
*/ | |||
public ClassPool(ClassPool src) { | |||
this(src, null); | |||
} | |||
private Hashtable cflow = null; // should be synchronous. | |||
/** | |||
* Creates a class pool. | |||
* | |||
* @param src the source of class files. If it is null, | |||
* the class search path is initially null. | |||
* @param trans the translator linked to this class pool. | |||
* It may be null. | |||
* @param p the parent of this class pool. | |||
* @see javassist.ClassPool#getDefault() | |||
*/ | |||
public ClassPool(ClassPool src, Translator trans) | |||
throws RuntimeException | |||
{ | |||
classes = new Hashtable(); | |||
CtClass[] pt = CtClass.primitiveTypes; | |||
for (int i = 0; i < pt.length; ++i) | |||
classes.put(pt[i].getName(), pt[i]); | |||
public ClassPool(ClassPool p) { | |||
this(new ClassPoolTail(), p); | |||
} | |||
if (src != null) | |||
source = src; | |||
else | |||
source = new ClassPoolTail(); | |||
ClassPool(AbsClassPool src, ClassPool parent) { | |||
this.classes = new Hashtable(); | |||
this.source = src; | |||
this.parent = parent; | |||
if (parent == null) { | |||
// if this has no parent, it must include primitive types | |||
// even if this.source is not a ClassPoolTail. | |||
CtClass[] pt = CtClass.primitiveTypes; | |||
for (int i = 0; i < pt.length; ++i) | |||
classes.put(pt[i].getName(), pt[i]); | |||
} | |||
translator = trans; | |||
if (trans != null) | |||
try { | |||
trans.start(this); | |||
} | |||
catch (Exception e) { | |||
throw new RuntimeException( | |||
"Translator.start() throws an exception: " | |||
+ e.toString()); | |||
} | |||
this.translator = null; | |||
this.cflow = null; | |||
} | |||
protected ClassPool() { | |||
source = null; | |||
classes = null; | |||
translator = null; | |||
/** | |||
* Inserts a new translator at the head of the translator chain. | |||
* | |||
* @param trans a new translator associated with this class pool. | |||
* @throws RuntimeException if trans.start() throws an exception. | |||
*/ | |||
public void insertTranslator(Translator trans) throws RuntimeException { | |||
ClassPool next = new ClassPool(source, parent); | |||
next.translator = trans; | |||
source = next; | |||
try { | |||
trans.start(next); | |||
} | |||
catch (Exception e) { | |||
throw new RuntimeException( | |||
"Translator.start() throws an exception: " | |||
+ e.toString()); | |||
} | |||
} | |||
/** | |||
@@ -188,15 +164,11 @@ public class ClassPool { | |||
* | |||
* @param t null or the translator linked to the class pool. | |||
*/ | |||
public static synchronized ClassPool getDefault(Translator t) { | |||
public static synchronized ClassPool getDefault() { | |||
if (defaultPool == null) { | |||
ClassPoolTail tail = new ClassPoolTail(); | |||
tail.appendSystemPath(); | |||
defaultPool = new ClassPool(tail, t); | |||
defaultPool = new ClassPool(null); | |||
defaultPool.appendSystemPath(); | |||
} | |||
else if (defaultPool.translator != t) | |||
throw new RuntimeException( | |||
"has been created with a different translator"); | |||
return defaultPool; | |||
} | |||
@@ -204,16 +176,26 @@ public class ClassPool { | |||
private static ClassPool defaultPool = null; | |||
/** | |||
* Returns the default class pool. | |||
* The returned object is always identical. | |||
* Provide a hook so that subclasses can do their own | |||
* caching of classes | |||
* | |||
* <p>This returns the result of <code>getDefault(null)</code>. | |||
* @see #removeCached(String) | |||
*/ | |||
protected CtClass getCached(String classname) | |||
{ | |||
return (CtClass)classes.get(classname); | |||
} | |||
/** | |||
* Provide a hook so that subclasses can do their own | |||
* caching of classes | |||
* | |||
* @see #getDefault(Translator) | |||
* @see #getCached(String) | |||
*/ | |||
public static ClassPool getDefault() { | |||
return getDefault(null); | |||
} | |||
protected void removeCached(String classname) | |||
{ | |||
classes.remove(classname); | |||
} | |||
/** | |||
* Returns the class search path. | |||
@@ -223,8 +205,8 @@ public class ClassPool { | |||
} | |||
/** | |||
* Records a name that never exists. For example, a package name | |||
* can be recorded by this method. | |||
* Records a name that never exists. | |||
* For example, a package name can be recorded by this method. | |||
* This would improve execution performance | |||
* since <code>get()</code> does not search the class path at all | |||
* if the given name is an invalid name recorded by this method. | |||
@@ -239,13 +221,10 @@ public class ClassPool { | |||
/** | |||
* Returns the <code>Translator</code> object associated with | |||
* this <code>ClassPool</code>. | |||
* | |||
* @deprecated | |||
*/ | |||
public Translator getTranslator() { return translator; } | |||
/** | |||
* Table of registered cflow variables. | |||
*/ | |||
private Hashtable cflow = null; // should be synchronous. | |||
Translator getTranslator() { return translator; } | |||
/** | |||
* Records the <code>$cflow</code> variable for the field specified | |||
@@ -425,7 +404,7 @@ public class ClassPool { | |||
/** | |||
* Returns a <code>java.lang.Class</code> object that has been loaded | |||
* by <code>writeAsClass()</code>. That object cannot be | |||
* by <code>writeAsClass()</code>. Such an object cannot be | |||
* obtained by <code>java.lang.Class.forName()</code> because it has | |||
* been loaded by an internal class loader of Javassist. | |||
* | |||
@@ -526,6 +505,17 @@ public class ClassPool { | |||
boolean callback) | |||
throws NotFoundException, CannotCompileException, IOException | |||
{ | |||
if (!write0(classname, out, callback)) | |||
throw new NotFoundException(classname); | |||
} | |||
boolean write0(String classname, DataOutputStream out, boolean callback) | |||
throws NotFoundException, CannotCompileException, IOException | |||
{ | |||
// first, delegate to the parent. | |||
if (parent != null && parent.write0(classname, out, callback)) | |||
return true; | |||
CtClass clazz = (CtClass)getCached(classname); | |||
if (callback && translator != null | |||
&& (clazz == null || !clazz.isFrozen())) { | |||
@@ -538,49 +528,76 @@ public class ClassPool { | |||
if (clazz != null) | |||
clazz.freeze(); | |||
source.write(classname, out); | |||
return source.write0(classname, out, callback); | |||
} | |||
else | |||
else { | |||
clazz.toBytecode(out); | |||
return true; | |||
} | |||
} | |||
/* for CtClassType.getClassFile2() | |||
/* for CtClassType.getClassFile2(). Don't delegate to the parent. | |||
*/ | |||
byte[] readSource(String classname) | |||
throws NotFoundException, IOException, CannotCompileException | |||
{ | |||
return source.write(classname); | |||
return source.readSource(classname); | |||
} | |||
/* | |||
* Is invoked by CtClassType.setName(). | |||
* Is invoked by CtClassType.setName(). Don't delegate to the parent. | |||
*/ | |||
synchronized void classNameChanged(String oldname, CtClass clazz) { | |||
CtClass c = (CtClass)getCached(oldname); | |||
if (c == clazz) // must check this equation | |||
removeCached(oldname); | |||
if (c == clazz) // must check this equation. | |||
removeCached(oldname); // see getAndRename(). | |||
String newName = clazz.getName(); | |||
checkNotFrozen(newName, "the class with the new name is frozen."); | |||
checkNotFrozen(newName); | |||
classes.put(newName, clazz); | |||
} | |||
/* | |||
* Is invoked by CtClassType.setName() and methods in this class. | |||
* This method throws an exception if the class is already frozen or | |||
* if this class pool cannot edit the class since it is in a parent | |||
* class pool. | |||
*/ | |||
void checkNotFrozen(String classname, String errmsg) | |||
throws RuntimeException | |||
{ | |||
CtClass c = getCached(classname); | |||
void checkNotFrozen(String classname) throws RuntimeException { | |||
CtClass c; | |||
if (parent != null) { | |||
try { | |||
c = parent.get0(classname); | |||
} | |||
catch (NotFoundException e) { // some error happens. | |||
throw new RuntimeException(e.toString()); | |||
} | |||
if (c != null) | |||
throw new RuntimeException(classname | |||
+ " is in a parent ClassPool. Use the parent."); | |||
} | |||
c = getCached(classname); | |||
if (c != null && c.isFrozen()) | |||
throw new RuntimeException(errmsg); | |||
throw new RuntimeException(classname + | |||
": frozen class (cannot edit)"); | |||
} | |||
/** | |||
* Reads a class file and constructs a <code>CtClass</code> | |||
* object with a new name. | |||
* This method is useful if that class file has been already | |||
* loaded and the resulting class is frozen. | |||
* This method is useful if you want to generate a new class as a copy | |||
* of another class (except the class name). For example, | |||
* | |||
* <ul><pre> | |||
* getAndRename("Point", "Pair") | |||
* </pre></ul> | |||
* | |||
* returns a <code>CtClass</code> object representing <code>Pair</code> | |||
* class. The definition of <code>Pair</code> is the same as that of | |||
* <code>Point</code> class except the class name since <code>Pair</code> | |||
* is defined by reading <code>Point.class</code>. | |||
* | |||
* @param orgName the original (fully-qualified) class name | |||
* @param newName the new class name | |||
@@ -588,7 +605,16 @@ public class ClassPool { | |||
public CtClass getAndRename(String orgName, String newName) | |||
throws NotFoundException | |||
{ | |||
CtClass clazz = get0(orgName); | |||
CtClass clazz = null; | |||
if (parent != null) | |||
clazz = parent.get1(orgName); | |||
if (clazz == null) | |||
clazz = get1(orgName); | |||
if (clazz == null) | |||
throw new NotFoundException(orgName); | |||
clazz.setName(newName); // indirectly calls | |||
// classNameChanged() in this class | |||
return clazz; | |||
@@ -610,25 +636,61 @@ public class ClassPool { | |||
* | |||
* @param classname a fully-qualified class name. | |||
*/ | |||
public synchronized CtClass get(String classname) | |||
public CtClass get(String classname) throws NotFoundException { | |||
CtClass clazz = get0(classname); | |||
if (clazz == null) | |||
throw new NotFoundException(classname); | |||
else | |||
return clazz; | |||
} | |||
/** | |||
* @return null if the class could not be found. | |||
*/ | |||
private synchronized CtClass get0(String classname) | |||
throws NotFoundException | |||
{ | |||
CtClass clazz = getCached(classname); | |||
CtClass clazz; | |||
if (parent != null) { | |||
clazz = parent.get0(classname); | |||
if (clazz != null) | |||
return clazz; | |||
} | |||
clazz = getCached(classname); | |||
if (clazz == null) { | |||
clazz = get0(classname); | |||
classes.put(classname, clazz); | |||
clazz = get1(classname); | |||
if (clazz != null) | |||
classes.put(classname, clazz); | |||
} | |||
return clazz; | |||
} | |||
protected CtClass get0(String classname) throws NotFoundException { | |||
if (classname.endsWith("[]")) | |||
return new CtArray(classname, this); | |||
else { | |||
checkClassName(classname); | |||
return new CtClassType(classname, this); | |||
private CtClass get1(String classname) throws NotFoundException { | |||
if (classname.endsWith("[]")) { | |||
String base = classname.substring(0, classname.indexOf('[')); | |||
if (getCached(base) == null && find(base) == null) | |||
return null; | |||
else | |||
return new CtArray(classname, this); | |||
} | |||
else | |||
if (find(classname) == null) | |||
return null; | |||
else | |||
return new CtClassType(classname, this); | |||
} | |||
/** | |||
* Obtains the URL of the class file specified by classname. | |||
* This method does not delegate to the parent pool. | |||
* | |||
* @param classname a fully-qualified class name. | |||
* @return null if the class file could not be found. | |||
*/ | |||
URL find(String classname) { | |||
return source.find(classname); | |||
} | |||
/** | |||
@@ -670,7 +732,7 @@ public class ClassPool { | |||
} | |||
/** | |||
* Creates a new class from the given class file. | |||
* Creates a new class (or interface) from the given class file. | |||
* If there already exists a class with the same name, the new class | |||
* overwrites that previous class. | |||
* | |||
@@ -689,8 +751,7 @@ public class ClassPool { | |||
CtClass clazz = new CtClassType(classfile, this); | |||
clazz.checkModify(); | |||
String classname = clazz.getName(); | |||
checkNotFrozen(classname, | |||
"there is a frozen class with the same name."); | |||
checkNotFrozen(classname); | |||
classes.put(classname, clazz); | |||
return clazz; | |||
} | |||
@@ -719,8 +780,7 @@ public class ClassPool { | |||
public synchronized CtClass makeClass(String classname, CtClass superclass) | |||
throws RuntimeException | |||
{ | |||
checkNotFrozen(classname, | |||
"the class with the given name is frozen."); | |||
checkNotFrozen(classname); | |||
CtClass clazz = new CtNewClass(classname, this, false, superclass); | |||
classes.put(classname, clazz); | |||
return clazz; | |||
@@ -750,33 +810,12 @@ public class ClassPool { | |||
public synchronized CtClass makeInterface(String name, CtClass superclass) | |||
throws RuntimeException | |||
{ | |||
checkNotFrozen(name, | |||
"the interface with the given name is frozen."); | |||
checkNotFrozen(name); | |||
CtClass clazz = new CtNewClass(name, this, true, superclass); | |||
classes.put(name, clazz); | |||
return clazz; | |||
} | |||
/** | |||
* Throws an exception if the class with the specified name does not | |||
* exist. | |||
*/ | |||
void checkClassName(String classname) | |||
throws NotFoundException | |||
{ | |||
source.checkClassName(classname); | |||
} | |||
/** | |||
* Obtains the URL of the class file specified by classname. | |||
* | |||
* @param classname a fully-qualified class name. | |||
* @return null if the class file could not be found. | |||
*/ | |||
public URL find(String classname) { | |||
return source.find(classname); | |||
} | |||
/** | |||
* Appends the system search path to the end of the | |||
* search path. The system search path | |||
@@ -854,7 +893,7 @@ public class ClassPool { | |||
* The detached <code>ClassPath</code> object cannot be added | |||
* to the pathagain. | |||
*/ | |||
public synchronized void removeClassPath(ClassPath cp) { | |||
public void removeClassPath(ClassPath cp) { | |||
source.removeClassPath(cp); | |||
} | |||
@@ -163,14 +163,12 @@ final class JarClassPath implements ClassPath { | |||
} | |||
} | |||
final class ClassPoolTail extends ClassPool { | |||
final class ClassPoolTail extends AbsClassPool { | |||
protected ClassPathList pathList; | |||
private Class thisClass; | |||
private Hashtable packages; // should be synchronized. | |||
public ClassPoolTail() { | |||
pathList = null; | |||
thisClass = getClass(); | |||
packages = new Hashtable(); | |||
} | |||
@@ -196,33 +194,44 @@ final class ClassPoolTail extends ClassPool { | |||
packages.put(name, name); | |||
} | |||
public byte[] write(String classname) | |||
throws NotFoundException, IOException | |||
/** | |||
* @return the contents of the class file. | |||
* @throws NotFoundException if the file could not be found. | |||
*/ | |||
byte[] readSource(String classname) | |||
throws NotFoundException, IOException, CannotCompileException | |||
{ | |||
return readClassfile(classname); | |||
byte[] b = readClassfile(classname); | |||
if (b == null) | |||
throw new NotFoundException(classname); | |||
else | |||
return b; | |||
} | |||
public void write(String classname, DataOutputStream out) | |||
/** | |||
* @return null if the file could not be found. | |||
* @throws NotFoundException if any error is reported by ClassPath. | |||
*/ | |||
boolean write0(String classname, DataOutputStream out, boolean callback) | |||
throws NotFoundException, CannotCompileException, IOException | |||
{ | |||
byte[] b = write(classname); | |||
out.write(b, 0, b.length); | |||
} | |||
public CtClass get(String classname) throws NotFoundException { | |||
throw new RuntimeException("fatal error"); | |||
} | |||
public CtClass makeClass(String classname) { | |||
throw new RuntimeException("fatal error"); | |||
byte[] b = readClassfile(classname); | |||
if (b == null) | |||
return false; // not found | |||
else { | |||
out.write(b, 0, b.length); | |||
return true; | |||
} | |||
} | |||
/* | |||
-- faster version -- | |||
void checkClassName(String classname) throws NotFoundException { | |||
if (find(classname) == null) | |||
throw new NotFoundException(classname); | |||
} | |||
/* slower version. | |||
-- slower version -- | |||
void checkClassName(String classname) throws NotFoundException { | |||
InputStream fin = openClassfile(classname); | |||
@@ -303,11 +312,16 @@ final class ClassPoolTail extends ClassPool { | |||
* specified by <code>classname</code>. | |||
* | |||
* @param classname a fully-qualified class name | |||
* @return null if the file has not been found. | |||
* @throws NotFoundException if any error is reported by ClassPath. | |||
*/ | |||
byte[] readClassfile(String classname) | |||
private byte[] readClassfile(String classname) | |||
throws NotFoundException, IOException | |||
{ | |||
InputStream fin = openClassfile(classname); | |||
if (fin == null) | |||
return null; | |||
byte[] b; | |||
try { | |||
b = readStream(fin); | |||
@@ -323,13 +337,15 @@ final class ClassPoolTail extends ClassPool { | |||
* Opens the class file for the class specified by | |||
* <code>classname</code>. | |||
* | |||
* @param classname a fully-qualified class name | |||
* @param classname a fully-qualified class name | |||
* @return null if the file has not been found. | |||
* @throws NotFoundException if any error is reported by ClassPath. | |||
*/ | |||
public InputStream openClassfile(String classname) | |||
private InputStream openClassfile(String classname) | |||
throws NotFoundException | |||
{ | |||
if (packages.get(classname) != null) | |||
throw new NotFoundException(classname); | |||
return null; // not found | |||
ClassPathList list = pathList; | |||
InputStream ins = null; | |||
@@ -352,7 +368,7 @@ final class ClassPoolTail extends ClassPool { | |||
if (error != null) | |||
throw error; | |||
else | |||
throw new NotFoundException(classname); | |||
return null; // not found | |||
} | |||
/** |
@@ -180,8 +180,8 @@ class CtClassType extends CtClass { | |||
if (name.equals(oldname)) | |||
return; | |||
classPool.checkNotFrozen(name, | |||
"the class with the new name is frozen"); | |||
// check this in advance although classNameChanged() below does. | |||
classPool.checkNotFrozen(name); | |||
ClassFile cf = getClassFile2(); | |||
super.setName(name); | |||
cf.setName(name); | |||
@@ -197,8 +197,8 @@ class CtClassType extends CtClass { | |||
= (String)classnames.get(Descriptor.toJvmName(oldClassName)); | |||
if (newClassName != null) { | |||
newClassName = Descriptor.toJavaName(newClassName); | |||
classPool.checkNotFrozen(newClassName, | |||
"the class " + newClassName + " is frozen"); | |||
// check this in advance although classNameChanged() below does. | |||
classPool.checkNotFrozen(newClassName); | |||
} | |||
super.replaceClassName(classnames); |
@@ -43,7 +43,7 @@ public interface Translator { | |||
* Is invoked by a <code>ClassPool</code> for notifying that | |||
* a class is written out to an output stream. | |||
* | |||
* <p>If CtClass.frozen() is true, that is, if the class has been | |||
* <p>If <code>CtClass.frozen()</code> is true, that is, if the class has been | |||
* already modified and written, then onWrite() is not invoked. | |||
* | |||
* @param pool the <code>ClassPool</code> that this translator |
@@ -28,228 +28,211 @@ import java.util.LinkedList; | |||
* | |||
* @see javassist.CtField#getFieldInfo() | |||
*/ | |||
public final class FieldInfo | |||
{ | |||
ConstPool constPool; | |||
int accessFlags; | |||
int name; | |||
int descriptor; | |||
LinkedList attribute; // may be null. | |||
AnnotationGroup runtimeInvisible; | |||
AnnotationGroup runtimeVisible; | |||
private FieldInfo(ConstPool cp) | |||
{ | |||
constPool = cp; | |||
accessFlags = 0; | |||
attribute = null; | |||
} | |||
/** | |||
* Constructs a <code>field_info</code> structure. | |||
* | |||
* @param cp a constant pool table | |||
* @param fieldName field name | |||
* @param desc field descriptor | |||
* | |||
* @see Descriptor | |||
*/ | |||
public FieldInfo(ConstPool cp, String fieldName, String desc) | |||
{ | |||
this(cp); | |||
name = cp.addUtf8Info(fieldName); | |||
descriptor = cp.addUtf8Info(desc); | |||
} | |||
FieldInfo(ConstPool cp, DataInputStream in) throws IOException | |||
{ | |||
this(cp); | |||
read(in); | |||
} | |||
/** | |||
* Returns the constant pool table used | |||
* by this <code>field_info</code>. | |||
*/ | |||
public ConstPool getConstPool() | |||
{ | |||
return constPool; | |||
} | |||
/** | |||
* Returns the field name. | |||
*/ | |||
public String getName() | |||
{ | |||
return constPool.getUtf8Info(name); | |||
} | |||
/** | |||
* Sets the field name. | |||
*/ | |||
public void setName(String newName) | |||
{ | |||
name = constPool.addUtf8Info(newName); | |||
} | |||
/** | |||
* Returns the access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public int getAccessFlags() | |||
{ | |||
return accessFlags; | |||
} | |||
/** | |||
* Sets the access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public void setAccessFlags(int acc) | |||
{ | |||
accessFlags = acc; | |||
} | |||
/** | |||
* Returns the field descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public String getDescriptor() | |||
{ | |||
return constPool.getUtf8Info(descriptor); | |||
} | |||
/** | |||
* Sets the field descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public void setDescriptor(String desc) | |||
{ | |||
if (!desc.equals(getDescriptor())) | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
/** | |||
* Returns all the attributes. | |||
* | |||
* @return a list of <code>AttributeInfo</code> objects. | |||
* @see AttributeInfo | |||
*/ | |||
public List getAttributes() | |||
{ | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
return attribute; | |||
} | |||
/** | |||
* Returns the attribute with the specified name. | |||
* | |||
* @param name attribute name | |||
*/ | |||
public AttributeInfo getAttribute(String name) | |||
{ | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with | |||
* the same name, the new one substitutes for it. | |||
*/ | |||
public void addAttribute(AttributeInfo info) | |||
{ | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
AttributeInfo.remove(attribute, info.getName()); | |||
attribute.add(info); | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeInvisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeInvisibleGroup() | |||
{ | |||
if (runtimeInvisible == null) | |||
{ | |||
AttributeInfo attr = new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeInvisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeVisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeVisibleGroup() | |||
{ | |||
if (runtimeVisible == null) | |||
{ | |||
AttributeInfo attr = new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeVisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime invisible annotations as pertains to the | |||
* CLASS RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeInvisibleAnnotations() | |||
{ | |||
if (runtimeInvisible != null) return runtimeInvisible; | |||
AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); | |||
if (invisible == null) return null; | |||
runtimeInvisible = new AnnotationGroup(invisible); | |||
return runtimeInvisible; | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime visible annotations as pertains to the | |||
* RUNTIME RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeVisibleAnnotations() | |||
{ | |||
if (runtimeVisible != null) return runtimeVisible; | |||
AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); | |||
if (visible == null) return null; | |||
runtimeVisible = new AnnotationGroup(visible); | |||
return runtimeVisible; | |||
} | |||
private void read(DataInputStream in) throws IOException | |||
{ | |||
accessFlags = in.readUnsignedShort(); | |||
name = in.readUnsignedShort(); | |||
descriptor = in.readUnsignedShort(); | |||
int n = in.readUnsignedShort(); | |||
attribute = new LinkedList(); | |||
for (int i = 0; i < n; ++i) | |||
attribute.add(AttributeInfo.read(constPool, in)); | |||
} | |||
void write(DataOutputStream out) throws IOException | |||
{ | |||
out.writeShort(accessFlags); | |||
out.writeShort(name); | |||
out.writeShort(descriptor); | |||
if (attribute == null) | |||
out.writeShort(0); | |||
else | |||
{ | |||
out.writeShort(attribute.size()); | |||
AttributeInfo.writeAll(attribute, out); | |||
} | |||
} | |||
public final class FieldInfo { | |||
ConstPool constPool; | |||
int accessFlags; | |||
int name; | |||
int descriptor; | |||
LinkedList attribute; // may be null. | |||
AnnotationGroup runtimeInvisible; | |||
AnnotationGroup runtimeVisible; | |||
private FieldInfo(ConstPool cp) { | |||
constPool = cp; | |||
accessFlags = 0; | |||
attribute = null; | |||
} | |||
/** | |||
* Constructs a <code>field_info</code> structure. | |||
* | |||
* @param cp a constant pool table | |||
* @param fieldName field name | |||
* @param desc field descriptor | |||
* | |||
* @see Descriptor | |||
*/ | |||
public FieldInfo(ConstPool cp, String fieldName, String desc) { | |||
this(cp); | |||
name = cp.addUtf8Info(fieldName); | |||
descriptor = cp.addUtf8Info(desc); | |||
} | |||
FieldInfo(ConstPool cp, DataInputStream in) throws IOException { | |||
this(cp); | |||
read(in); | |||
} | |||
/** | |||
* Returns the constant pool table used | |||
* by this <code>field_info</code>. | |||
*/ | |||
public ConstPool getConstPool() { | |||
return constPool; | |||
} | |||
/** | |||
* Returns the field name. | |||
*/ | |||
public String getName() { | |||
return constPool.getUtf8Info(name); | |||
} | |||
/** | |||
* Sets the field name. | |||
*/ | |||
public void setName(String newName) { | |||
name = constPool.addUtf8Info(newName); | |||
} | |||
/** | |||
* Returns the access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public int getAccessFlags() { | |||
return accessFlags; | |||
} | |||
/** | |||
* Sets the access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public void setAccessFlags(int acc) { | |||
accessFlags = acc; | |||
} | |||
/** | |||
* Returns the field descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public String getDescriptor() { | |||
return constPool.getUtf8Info(descriptor); | |||
} | |||
/** | |||
* Sets the field descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public void setDescriptor(String desc) { | |||
if (!desc.equals(getDescriptor())) | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
/** | |||
* Returns all the attributes. | |||
* | |||
* @return a list of <code>AttributeInfo</code> objects. | |||
* @see AttributeInfo | |||
*/ | |||
public List getAttributes() { | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
return attribute; | |||
} | |||
/** | |||
* Returns the attribute with the specified name. | |||
* | |||
* @param name attribute name | |||
*/ | |||
public AttributeInfo getAttribute(String name) { | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with | |||
* the same name, the new one substitutes for it. | |||
*/ | |||
public void addAttribute(AttributeInfo info) { | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
AttributeInfo.remove(attribute, info.getName()); | |||
attribute.add(info); | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeInvisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeInvisibleGroup() { | |||
if (runtimeInvisible == null) { | |||
AttributeInfo attr = | |||
new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeInvisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeVisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeVisibleGroup() { | |||
if (runtimeVisible == null) { | |||
AttributeInfo attr = | |||
new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeVisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime invisible annotations as pertains to the | |||
* CLASS RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeInvisibleAnnotations() { | |||
if (runtimeInvisible != null) | |||
return runtimeInvisible; | |||
AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); | |||
if (invisible == null) | |||
return null; | |||
runtimeInvisible = new AnnotationGroup(invisible); | |||
return runtimeInvisible; | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime visible annotations as pertains to the | |||
* RUNTIME RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeVisibleAnnotations() { | |||
if (runtimeVisible != null) | |||
return runtimeVisible; | |||
AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); | |||
if (visible == null) | |||
return null; | |||
runtimeVisible = new AnnotationGroup(visible); | |||
return runtimeVisible; | |||
} | |||
private void read(DataInputStream in) throws IOException { | |||
accessFlags = in.readUnsignedShort(); | |||
name = in.readUnsignedShort(); | |||
descriptor = in.readUnsignedShort(); | |||
int n = in.readUnsignedShort(); | |||
attribute = new LinkedList(); | |||
for (int i = 0; i < n; ++i) | |||
attribute.add(AttributeInfo.read(constPool, in)); | |||
} | |||
void write(DataOutputStream out) throws IOException { | |||
out.writeShort(accessFlags); | |||
out.writeShort(name); | |||
out.writeShort(descriptor); | |||
if (attribute == null) | |||
out.writeShort(0); | |||
else { | |||
out.writeShort(attribute.size()); | |||
AttributeInfo.writeAll(attribute, out); | |||
} | |||
} | |||
} |
@@ -30,444 +30,414 @@ import java.util.LinkedList; | |||
* @see javassist.CtMethod#getMethodInfo() | |||
* @see javassist.CtConstructor#getMethodInfo() | |||
*/ | |||
public final class MethodInfo | |||
{ | |||
ConstPool constPool; | |||
int accessFlags; | |||
int name; | |||
int descriptor; | |||
LinkedList attribute; // may be null | |||
AnnotationGroup runtimeInvisible; | |||
AnnotationGroup runtimeVisible; | |||
/** | |||
* The name of constructors: <code><init></code>. | |||
*/ | |||
public static final String nameInit = "<init>"; | |||
/** | |||
* The name of class initializer (static initializer): | |||
* <code><clinit></code>. | |||
*/ | |||
public static final String nameClinit = "<clinit>"; | |||
private MethodInfo(ConstPool cp) | |||
{ | |||
constPool = cp; | |||
attribute = null; | |||
} | |||
/** | |||
* Constructs a <code>method_info</code> structure. | |||
* | |||
* @param cp a constant pool table | |||
* @param methodname method name | |||
* @param desc method descriptor | |||
* | |||
* @see Descriptor | |||
*/ | |||
public MethodInfo(ConstPool cp, String methodname, String desc) | |||
{ | |||
this(cp); | |||
accessFlags = 0; | |||
name = cp.addUtf8Info(methodname); | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
MethodInfo(ConstPool cp, DataInputStream in) throws IOException | |||
{ | |||
this(cp); | |||
read(in); | |||
} | |||
/** | |||
* Constructs a copy of <code>method_info</code> structure. | |||
* Class names appearing in the source <code>method_info</code> | |||
* are renamed according to <code>classnameMap</code>. | |||
* | |||
* <p>Note: only <code>Code</code> and <code>Exceptions</code> | |||
* attributes are copied from the source. The other attributes | |||
* are ignored. | |||
* | |||
* @param cp a constant pool table | |||
* @param methodname a method name | |||
* @param src a source <code>method_info</code> | |||
* @param classnameMap specifies pairs of replaced and substituted | |||
* name. | |||
* @see Descriptor | |||
*/ | |||
public MethodInfo(ConstPool cp, String methodname, MethodInfo src, | |||
Map classnameMap) throws BadBytecode | |||
{ | |||
this(cp); | |||
read(src, methodname, classnameMap); | |||
} | |||
/** | |||
* Returns a method name. | |||
*/ | |||
public String getName() | |||
{ | |||
return constPool.getUtf8Info(name); | |||
} | |||
/** | |||
* Sets a method name. | |||
*/ | |||
public void setName(String newName) | |||
{ | |||
name = constPool.addUtf8Info(newName); | |||
} | |||
/** | |||
* Returns true if this is not a constructor or a class initializer | |||
* (static initializer). | |||
*/ | |||
public boolean isMethod() | |||
{ | |||
String n = getName(); | |||
return !n.equals(nameInit) && !n.equals(nameClinit); | |||
} | |||
/** | |||
* Returns a constant pool table used by this method. | |||
*/ | |||
public ConstPool getConstPool() | |||
{ | |||
return constPool; | |||
} | |||
/** | |||
* Returns true if this is a constructor. | |||
*/ | |||
public boolean isConstructor() | |||
{ | |||
return getName().equals(nameInit); | |||
} | |||
/** | |||
* Returns true if this is a class initializer (static initializer). | |||
*/ | |||
public boolean isStaticInitializer() | |||
{ | |||
return getName().equals(nameClinit); | |||
} | |||
/** | |||
* Returns access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public int getAccessFlags() | |||
{ | |||
return accessFlags; | |||
} | |||
/** | |||
* Sets access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public void setAccessFlags(int acc) | |||
{ | |||
accessFlags = acc; | |||
} | |||
/** | |||
* Returns a method descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public String getDescriptor() | |||
{ | |||
return constPool.getUtf8Info(descriptor); | |||
} | |||
/** | |||
* Sets a method descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public void setDescriptor(String desc) | |||
{ | |||
if (!desc.equals(getDescriptor())) | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
/** | |||
* Returns all the attributes. | |||
* | |||
* @return a list of <code>AttributeInfo</code> objects. | |||
* @see AttributeInfo | |||
*/ | |||
public List getAttributes() | |||
{ | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
return attribute; | |||
} | |||
/** | |||
* Returns the attribute with the specified name. | |||
* If it is not found, this method returns null. | |||
* | |||
* @param name attribute name | |||
* @return an <code>AttributeInfo</code> object or null. | |||
*/ | |||
public AttributeInfo getAttribute(String name) | |||
{ | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with | |||
* the same name, the new one substitutes for it. | |||
*/ | |||
public void addAttribute(AttributeInfo info) | |||
{ | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
AttributeInfo.remove(attribute, info.getName()); | |||
attribute.add(info); | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeInvisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeInvisibleGroup() | |||
{ | |||
if (runtimeInvisible == null) | |||
{ | |||
AttributeInfo attr = new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeInvisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeVisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeVisibleGroup() | |||
{ | |||
if (runtimeVisible == null) | |||
{ | |||
AttributeInfo attr = new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeVisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime invisible annotations as pertains to the | |||
* CLASS RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeInvisibleAnnotations() | |||
{ | |||
if (runtimeInvisible != null) return runtimeInvisible; | |||
AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); | |||
if (invisible == null) return null; | |||
runtimeInvisible = new AnnotationGroup(invisible); | |||
return runtimeInvisible; | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime visible annotations as pertains to the | |||
* RUNTIME RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeVisibleAnnotations() | |||
{ | |||
if (runtimeVisible != null) return runtimeVisible; | |||
AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); | |||
if (visible == null) return null; | |||
runtimeVisible = new AnnotationGroup(visible); | |||
return runtimeVisible; | |||
} | |||
/** | |||
* Returns an Exceptions attribute. | |||
* | |||
* @return an Exceptions attribute | |||
* or null if it is not specified. | |||
*/ | |||
public ExceptionsAttribute getExceptionsAttribute() | |||
{ | |||
AttributeInfo info | |||
= AttributeInfo.lookup(attribute, ExceptionsAttribute.class); | |||
return (ExceptionsAttribute) info; | |||
} | |||
/** | |||
* Returns a Code attribute. | |||
* | |||
* @return a Code attribute | |||
* or null if it is not specified. | |||
*/ | |||
public CodeAttribute getCodeAttribute() | |||
{ | |||
AttributeInfo info | |||
= AttributeInfo.lookup(attribute, CodeAttribute.class); | |||
return (CodeAttribute) info; | |||
} | |||
/** | |||
* Removes an Exception attribute. | |||
*/ | |||
public void removeExceptionsAttribute() | |||
{ | |||
AttributeInfo.remove(attribute, ExceptionsAttribute.class); | |||
} | |||
/** | |||
* Adds an Exception attribute. | |||
* | |||
* <p>The added attribute must share the same constant pool table | |||
* as this <code>method_info</code> structure. | |||
*/ | |||
public void setExceptionsAttribute(ExceptionsAttribute cattr) | |||
{ | |||
removeExceptionsAttribute(); | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
attribute.add(cattr); | |||
} | |||
/** | |||
* Removes a Code attribute. | |||
*/ | |||
public void removeCodeAttribute() | |||
{ | |||
AttributeInfo.remove(attribute, CodeAttribute.class); | |||
} | |||
/** | |||
* Adds a Code attribute. | |||
* | |||
* <p>The added attribute must share the same constant pool table | |||
* as this <code>method_info</code> structure. | |||
*/ | |||
public void setCodeAttribute(CodeAttribute cattr) | |||
{ | |||
removeCodeAttribute(); | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
attribute.add(cattr); | |||
} | |||
/** | |||
* Returns the line number of the source line corresponding to the | |||
* specified bytecode contained in this method. | |||
* | |||
* @param pos the position of the bytecode (>= 0). | |||
* an index into the code array. | |||
* @return -1 if this information is not available. | |||
*/ | |||
public int getLineNumber(int pos) | |||
{ | |||
CodeAttribute ca = getCodeAttribute(); | |||
if (ca == null) | |||
return -1; | |||
LineNumberAttribute ainfo | |||
= (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag); | |||
if (ainfo == null) | |||
return -1; | |||
return ainfo.toLineNumber(pos); | |||
} | |||
/** | |||
* Changes a super constructor called by this constructor. | |||
* | |||
* <p>This method modifies a call to <code>super()</code>, | |||
* which should be at the | |||
* head of a constructor body, so that a constructor in a different | |||
* super class is called. This method does not change actural | |||
* parameters. Hence the new super class must have a constructor | |||
* with the same signature as the original one. | |||
* | |||
* <p>This method should be called when the super class | |||
* of the class declaring this method is changed. | |||
* | |||
* <p>This method does not perform anything unless this | |||
* <code>MethodInfo</code> represents a constructor. | |||
* | |||
* @param superclass the new super class | |||
*/ | |||
public void setSuperclass(String superclass) throws BadBytecode | |||
{ | |||
if (!isConstructor()) | |||
return; | |||
CodeAttribute ca = getCodeAttribute(); | |||
byte[] code = ca.getCode(); | |||
CodeIterator iterator = ca.iterator(); | |||
int pos = iterator.skipSuperConstructor(); | |||
if (pos >= 0) | |||
{ // not this() | |||
ConstPool cp = constPool; | |||
int mref = ByteArray.readU16bit(code, pos + 1); | |||
int nt = cp.getMethodrefNameAndType(mref); | |||
int sc = cp.addClassInfo(superclass); | |||
int mref2 = cp.addMethodrefInfo(sc, nt); | |||
ByteArray.write16bit(mref2, code, pos + 1); | |||
} | |||
} | |||
private void read(MethodInfo src, String methodname, Map classnames) | |||
throws BadBytecode | |||
{ | |||
ConstPool destCp = constPool; | |||
accessFlags = src.accessFlags; | |||
name = destCp.addUtf8Info(methodname); | |||
ConstPool srcCp = src.constPool; | |||
String desc = srcCp.getUtf8Info(src.descriptor); | |||
String desc2 = Descriptor.rename(desc, classnames); | |||
descriptor = destCp.addUtf8Info(desc2); | |||
attribute = new LinkedList(); | |||
ExceptionsAttribute eattr = src.getExceptionsAttribute(); | |||
if (eattr != null) | |||
attribute.add(eattr.copy(destCp, classnames)); | |||
CodeAttribute cattr = src.getCodeAttribute(); | |||
if (cattr != null) | |||
attribute.add(cattr.copy(destCp, classnames)); | |||
} | |||
private void read(DataInputStream in) throws IOException | |||
{ | |||
accessFlags = in.readUnsignedShort(); | |||
name = in.readUnsignedShort(); | |||
descriptor = in.readUnsignedShort(); | |||
int n = in.readUnsignedShort(); | |||
attribute = new LinkedList(); | |||
for (int i = 0; i < n; ++i) | |||
attribute.add(AttributeInfo.read(constPool, in)); | |||
} | |||
void write(DataOutputStream out) throws IOException | |||
{ | |||
out.writeShort(accessFlags); | |||
out.writeShort(name); | |||
out.writeShort(descriptor); | |||
if (attribute == null) | |||
out.writeShort(0); | |||
else | |||
{ | |||
out.writeShort(attribute.size()); | |||
AttributeInfo.writeAll(attribute, out); | |||
} | |||
} | |||
public final class MethodInfo { | |||
ConstPool constPool; | |||
int accessFlags; | |||
int name; | |||
int descriptor; | |||
LinkedList attribute; // may be null | |||
AnnotationGroup runtimeInvisible; | |||
AnnotationGroup runtimeVisible; | |||
/** | |||
* The name of constructors: <code><init></code>. | |||
*/ | |||
public static final String nameInit = "<init>"; | |||
/** | |||
* The name of class initializer (static initializer): | |||
* <code><clinit></code>. | |||
*/ | |||
public static final String nameClinit = "<clinit>"; | |||
private MethodInfo(ConstPool cp) { | |||
constPool = cp; | |||
attribute = null; | |||
} | |||
/** | |||
* Constructs a <code>method_info</code> structure. | |||
* | |||
* @param cp a constant pool table | |||
* @param methodname method name | |||
* @param desc method descriptor | |||
* | |||
* @see Descriptor | |||
*/ | |||
public MethodInfo(ConstPool cp, String methodname, String desc) { | |||
this(cp); | |||
accessFlags = 0; | |||
name = cp.addUtf8Info(methodname); | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
MethodInfo(ConstPool cp, DataInputStream in) throws IOException { | |||
this(cp); | |||
read(in); | |||
} | |||
/** | |||
* Constructs a copy of <code>method_info</code> structure. | |||
* Class names appearing in the source <code>method_info</code> | |||
* are renamed according to <code>classnameMap</code>. | |||
* | |||
* <p>Note: only <code>Code</code> and <code>Exceptions</code> | |||
* attributes are copied from the source. The other attributes | |||
* are ignored. | |||
* | |||
* @param cp a constant pool table | |||
* @param methodname a method name | |||
* @param src a source <code>method_info</code> | |||
* @param classnameMap specifies pairs of replaced and substituted | |||
* name. | |||
* @see Descriptor | |||
*/ | |||
public MethodInfo(ConstPool cp, String methodname, MethodInfo src, | |||
Map classnameMap) throws BadBytecode { | |||
this(cp); | |||
read(src, methodname, classnameMap); | |||
} | |||
/** | |||
* Returns a method name. | |||
*/ | |||
public String getName() { | |||
return constPool.getUtf8Info(name); | |||
} | |||
/** | |||
* Sets a method name. | |||
*/ | |||
public void setName(String newName) { | |||
name = constPool.addUtf8Info(newName); | |||
} | |||
/** | |||
* Returns true if this is not a constructor or a class initializer | |||
* (static initializer). | |||
*/ | |||
public boolean isMethod() { | |||
String n = getName(); | |||
return !n.equals(nameInit) && !n.equals(nameClinit); | |||
} | |||
/** | |||
* Returns a constant pool table used by this method. | |||
*/ | |||
public ConstPool getConstPool() { | |||
return constPool; | |||
} | |||
/** | |||
* Returns true if this is a constructor. | |||
*/ | |||
public boolean isConstructor() { | |||
return getName().equals(nameInit); | |||
} | |||
/** | |||
* Returns true if this is a class initializer (static initializer). | |||
*/ | |||
public boolean isStaticInitializer() { | |||
return getName().equals(nameClinit); | |||
} | |||
/** | |||
* Returns access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public int getAccessFlags() { | |||
return accessFlags; | |||
} | |||
/** | |||
* Sets access flags. | |||
* | |||
* @see AccessFlag | |||
*/ | |||
public void setAccessFlags(int acc) { | |||
accessFlags = acc; | |||
} | |||
/** | |||
* Returns a method descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public String getDescriptor() { | |||
return constPool.getUtf8Info(descriptor); | |||
} | |||
/** | |||
* Sets a method descriptor. | |||
* | |||
* @see Descriptor | |||
*/ | |||
public void setDescriptor(String desc) { | |||
if (!desc.equals(getDescriptor())) | |||
descriptor = constPool.addUtf8Info(desc); | |||
} | |||
/** | |||
* Returns all the attributes. | |||
* | |||
* @return a list of <code>AttributeInfo</code> objects. | |||
* @see AttributeInfo | |||
*/ | |||
public List getAttributes() { | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
return attribute; | |||
} | |||
/** | |||
* Returns the attribute with the specified name. | |||
* If it is not found, this method returns null. | |||
* | |||
* @param name attribute name | |||
* @return an <code>AttributeInfo</code> object or null. | |||
*/ | |||
public AttributeInfo getAttribute(String name) { | |||
return AttributeInfo.lookup(attribute, name); | |||
} | |||
/** | |||
* Appends an attribute. If there is already an attribute with | |||
* the same name, the new one substitutes for it. | |||
*/ | |||
public void addAttribute(AttributeInfo info) { | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
AttributeInfo.remove(attribute, info.getName()); | |||
attribute.add(info); | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeInvisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeInvisibleGroup() { | |||
if (runtimeInvisible == null) { | |||
AttributeInfo attr = | |||
new AttributeInfo(constPool, "RuntimeInvisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeInvisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Create an empty (null) attribute "RuntimeVisibleAnnotations" | |||
* Usually used so that you can start adding annotations to a particular thing | |||
*/ | |||
public void createRuntimeVisibleGroup() { | |||
if (runtimeVisible == null) { | |||
AttributeInfo attr = | |||
new AttributeInfo(constPool, "RuntimeVisibleAnnotations"); | |||
addAttribute(attr); | |||
runtimeVisible = new AnnotationGroup(attr); | |||
} | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime invisible annotations as pertains to the | |||
* CLASS RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeInvisibleAnnotations() { | |||
if (runtimeInvisible != null) | |||
return runtimeInvisible; | |||
AttributeInfo invisible = getAttribute("RuntimeInvisibleAnnotations"); | |||
if (invisible == null) | |||
return null; | |||
runtimeInvisible = new AnnotationGroup(invisible); | |||
return runtimeInvisible; | |||
} | |||
/** | |||
* Return access object for getting info about annotations | |||
* This returns runtime visible annotations as pertains to the | |||
* RUNTIME RetentionPolicy | |||
* @return | |||
*/ | |||
public AnnotationGroup getRuntimeVisibleAnnotations() { | |||
if (runtimeVisible != null) | |||
return runtimeVisible; | |||
AttributeInfo visible = getAttribute("RuntimeVisibleAnnotations"); | |||
if (visible == null) | |||
return null; | |||
runtimeVisible = new AnnotationGroup(visible); | |||
return runtimeVisible; | |||
} | |||
/** | |||
* Returns an Exceptions attribute. | |||
* | |||
* @return an Exceptions attribute | |||
* or null if it is not specified. | |||
*/ | |||
public ExceptionsAttribute getExceptionsAttribute() { | |||
AttributeInfo info | |||
= AttributeInfo.lookup(attribute, ExceptionsAttribute.class); | |||
return (ExceptionsAttribute)info; | |||
} | |||
/** | |||
* Returns a Code attribute. | |||
* | |||
* @return a Code attribute | |||
* or null if it is not specified. | |||
*/ | |||
public CodeAttribute getCodeAttribute() { | |||
AttributeInfo info | |||
= AttributeInfo.lookup(attribute, CodeAttribute.class); | |||
return (CodeAttribute)info; | |||
} | |||
/** | |||
* Removes an Exception attribute. | |||
*/ | |||
public void removeExceptionsAttribute() { | |||
AttributeInfo.remove(attribute, ExceptionsAttribute.class); | |||
} | |||
/** | |||
* Adds an Exception attribute. | |||
* | |||
* <p>The added attribute must share the same constant pool table | |||
* as this <code>method_info</code> structure. | |||
*/ | |||
public void setExceptionsAttribute(ExceptionsAttribute cattr) { | |||
removeExceptionsAttribute(); | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
attribute.add(cattr); | |||
} | |||
/** | |||
* Removes a Code attribute. | |||
*/ | |||
public void removeCodeAttribute() { | |||
AttributeInfo.remove(attribute, CodeAttribute.class); | |||
} | |||
/** | |||
* Adds a Code attribute. | |||
* | |||
* <p>The added attribute must share the same constant pool table | |||
* as this <code>method_info</code> structure. | |||
*/ | |||
public void setCodeAttribute(CodeAttribute cattr) { | |||
removeCodeAttribute(); | |||
if (attribute == null) | |||
attribute = new LinkedList(); | |||
attribute.add(cattr); | |||
} | |||
/** | |||
* Returns the line number of the source line corresponding to the | |||
* specified bytecode contained in this method. | |||
* | |||
* @param pos the position of the bytecode (>= 0). | |||
* an index into the code array. | |||
* @return -1 if this information is not available. | |||
*/ | |||
public int getLineNumber(int pos) { | |||
CodeAttribute ca = getCodeAttribute(); | |||
if (ca == null) | |||
return -1; | |||
LineNumberAttribute ainfo = | |||
(LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); | |||
if (ainfo == null) | |||
return -1; | |||
return ainfo.toLineNumber(pos); | |||
} | |||
/** | |||
* Changes a super constructor called by this constructor. | |||
* | |||
* <p>This method modifies a call to <code>super()</code>, | |||
* which should be at the | |||
* head of a constructor body, so that a constructor in a different | |||
* super class is called. This method does not change actural | |||
* parameters. Hence the new super class must have a constructor | |||
* with the same signature as the original one. | |||
* | |||
* <p>This method should be called when the super class | |||
* of the class declaring this method is changed. | |||
* | |||
* <p>This method does not perform anything unless this | |||
* <code>MethodInfo</code> represents a constructor. | |||
* | |||
* @param superclass the new super class | |||
*/ | |||
public void setSuperclass(String superclass) throws BadBytecode { | |||
if (!isConstructor()) | |||
return; | |||
CodeAttribute ca = getCodeAttribute(); | |||
byte[] code = ca.getCode(); | |||
CodeIterator iterator = ca.iterator(); | |||
int pos = iterator.skipSuperConstructor(); | |||
if (pos >= 0) { // not this() | |||
ConstPool cp = constPool; | |||
int mref = ByteArray.readU16bit(code, pos + 1); | |||
int nt = cp.getMethodrefNameAndType(mref); | |||
int sc = cp.addClassInfo(superclass); | |||
int mref2 = cp.addMethodrefInfo(sc, nt); | |||
ByteArray.write16bit(mref2, code, pos + 1); | |||
} | |||
} | |||
private void read(MethodInfo src, String methodname, Map classnames) | |||
throws BadBytecode | |||
{ | |||
ConstPool destCp = constPool; | |||
accessFlags = src.accessFlags; | |||
name = destCp.addUtf8Info(methodname); | |||
ConstPool srcCp = src.constPool; | |||
String desc = srcCp.getUtf8Info(src.descriptor); | |||
String desc2 = Descriptor.rename(desc, classnames); | |||
descriptor = destCp.addUtf8Info(desc2); | |||
attribute = new LinkedList(); | |||
ExceptionsAttribute eattr = src.getExceptionsAttribute(); | |||
if (eattr != null) | |||
attribute.add(eattr.copy(destCp, classnames)); | |||
CodeAttribute cattr = src.getCodeAttribute(); | |||
if (cattr != null) | |||
attribute.add(cattr.copy(destCp, classnames)); | |||
} | |||
private void read(DataInputStream in) throws IOException { | |||
accessFlags = in.readUnsignedShort(); | |||
name = in.readUnsignedShort(); | |||
descriptor = in.readUnsignedShort(); | |||
int n = in.readUnsignedShort(); | |||
attribute = new LinkedList(); | |||
for (int i = 0; i < n; ++i) | |||
attribute.add(AttributeInfo.read(constPool, in)); | |||
} | |||
void write(DataOutputStream out) throws IOException { | |||
out.writeShort(accessFlags); | |||
out.writeShort(name); | |||
out.writeShort(descriptor); | |||
if (attribute == null) | |||
out.writeShort(0); | |||
else { | |||
out.writeShort(attribute.size()); | |||
AttributeInfo.writeAll(attribute, out); | |||
} | |||
} | |||
} |
@@ -90,7 +90,8 @@ public class Compiler { | |||
throws Exception | |||
{ | |||
Reflection implementor = new Reflection(); | |||
ClassPool pool = ClassPool.getDefault(implementor); | |||
ClassPool pool = ClassPool.getDefault(); | |||
pool.insertTranslator(implementor); | |||
for (int i = 0; i < n; ++i) { | |||
CtClass c = pool.get(entries[i].classname); |
@@ -133,7 +133,9 @@ public class Loader extends javassist.Loader { | |||
delegateLoadingOf("javassist.reflect.Loader"); | |||
reflection = new Reflection(); | |||
setClassPool(ClassPool.getDefault(reflection)); | |||
ClassPool pool = ClassPool.getDefault(); | |||
pool.insertTranslator(reflection); | |||
setClassPool(pool); | |||
} | |||
/** |
@@ -60,7 +60,7 @@ public class AppletServer extends Webserver { | |||
public AppletServer(int port) | |||
throws IOException, NotFoundException, CannotCompileException | |||
{ | |||
this(ClassPool.getDefault(new StubGenerator()), port); | |||
this(ClassPool.getDefault(), new StubGenerator(), port); | |||
} | |||
/** | |||
@@ -72,16 +72,17 @@ public class AppletServer extends Webserver { | |||
public AppletServer(int port, ClassPool src) | |||
throws IOException, NotFoundException, CannotCompileException | |||
{ | |||
this(new ClassPool(src, new StubGenerator()), port); | |||
this(new ClassPool(src), new StubGenerator(), port); | |||
} | |||
private AppletServer(ClassPool loader, int port) | |||
private AppletServer(ClassPool loader, StubGenerator gen, int port) | |||
throws IOException, NotFoundException, CannotCompileException | |||
{ | |||
super(port); | |||
exportedNames = new Hashtable(); | |||
exportedObjects = new Vector(); | |||
stubGen = (StubGenerator)loader.getTranslator(); | |||
stubGen = gen; | |||
loader.insertTranslator(gen); | |||
setClassPool(loader); | |||
} | |||