<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>
<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.
<?xml version="1.0"?>\r
\r
-<!-- ======================================================================= -->\r
-<!-- JBoss build file -->\r
-<!-- ======================================================================= -->\r
+<!-- =================================================================== -->\r
+<!-- JBoss build file -->\r
+<!-- =================================================================== -->\r
\r
<project name="javassist" default="jar" basedir=".">\r
\r
<property name="dist-version" value="javassist-2.7"/>\r
\r
<property environment="env"/>\r
+ <property name="target.jar" value="javassist.jar"/>\r
<property name="src.dir" value="${basedir}/src/main"/>\r
<property name="build.dir" value="${basedir}/build"/>\r
<property name="build.classes.dir" value="${build.dir}/classes"/>\r
\r
+ <property name="run.dir" value="${build.classes.dir}"/>\r
+\r
<!-- Build classpath -->\r
<path id="classpath">\r
<pathelement location="${build.classes.dir}"/>\r
</target>\r
\r
<target name="jar" depends="compile">\r
- <jar jarfile="javassist.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">\r
+ <jar jarfile="${target.jar}" manifest="${src.dir}/META-INF/MANIFEST.MF">\r
<fileset dir="${build.classes.dir}">\r
<include name="**/*.class"/>\r
</fileset>\r
<target name="clean">\r
<delete dir="build"/>\r
<delete dir="html"/>\r
- <delete file="javassist.jar"/>\r
+ <delete file="${target.jar}"/>\r
<delete file="${dist-version}.zip"/>\r
</target>\r
-</project>\r
\r
+ <!-- =================================================================== -->\r
+ <!-- Run samples -->\r
+ <!-- =================================================================== -->\r
+\r
+ <target name = "sample-all"\r
+ depends="sample-test,sample-reflect,sample-duplicate,sample-vector">\r
+ <echo>** please run sample-rmi and sample-evolve separately **</echo>\r
+ </target>\r
+\r
+ <target name = "sample-test" depends="sample" >\r
+ <java fork="true" dir="${run.dir}" classname="sample.Test">\r
+ <classpath refid="classpath"/>\r
+ </java>\r
+ </target>\r
+\r
+ <target name = "sample-reflect" depends="sample" >\r
+ <java fork="true" dir="${run.dir}" classname="javassist.reflect.Loader">\r
+ <classpath refid="classpath"/>\r
+ <arg line="sample.reflect.Main Joe" />\r
+ </java>\r
+ </target>\r
+\r
+ <target name = "sample-duplicate" depends="sample" >\r
+ <echo>run sample.duplicate.Viewer without reflection</echo>\r
+ <java fork="true" dir="${run.dir}" classname="sample.duplicate.Viewer">\r
+ <classpath refid="classpath"/>\r
+ </java>\r
+ <echo>run sample.duplicate.Viewer with reflection</echo>\r
+ <java fork="true" dir="${run.dir}" classname="sample.duplicate.Main">\r
+ <classpath refid="classpath"/>\r
+ </java>\r
+ </target>\r
+\r
+ <target name = "sample-vector" depends="sample" >\r
+ <echo>javassist.preproc.Compiler sample/vector/Test.j</echo>\r
+ <java fork="true" dir="${run.dir}" classname="javassist.preproc.Compiler">\r
+ <classpath refid="classpath"/>\r
+ <arg line="sample/vector/Test.j"/>\r
+ </java>\r
+ <echo>javac sample/vector/Test.java</echo>\r
+ <javac srcdir="${build.classes.dir}"\r
+ destdir="${build.classes.dir}"\r
+ includes="sample/vector/Test.java">\r
+ <classpath refid="classpath"/>\r
+ </javac>\r
+ <java fork="true" dir="${run.dir}" classname="sample.vector.Test" />\r
+ </target>\r
+\r
+ <target name = "sample-rmi" depends="sample" >\r
+ <echo>** Please open sample/rmi/webdemo.html with your browser **</echo>\r
+ <java fork="true" dir="${run.dir}" classname="sample.rmi.Counter">\r
+ <classpath refid="classpath"/>\r
+ <arg value="5001" />\r
+ </java>\r
+ </target>\r
+\r
+ <target name = "sample-evolve" depends="sample" >\r
+ <echo>** Please open http://localhost:5003/demo.html with your browser **</echo>\r
+ <java fork="true" dir="${run.dir}" classname="sample.evolve.DemoLoader">\r
+ <classpath refid="classpath"/>\r
+ <arg value="5003" />\r
+ </java>\r
+ </target>\r
+\r
+</project>\r
}\r
\r
public static void main(String[] args) throws Exception {\r
- ClassPool pool = ClassPool.getDefault(null);\r
+ ClassPool pool = ClassPool.getDefault();\r
\r
CtClass cc = pool.get("sample.Test");\r
try {\r
* updatable. Then it runs main() in sample.evolve.DemoServer.\r
*/\r
public static void main(String[] args) throws Throwable {\r
- Evolution translator = new Evolution();\r
- ClassPool cp = ClassPool.getDefault(translator);\r
- Loader cl = new Loader();\r
- cl.setClassPool(cp);\r
+ Evolution translator = new Evolution();\r
+ ClassPool cp = ClassPool.getDefault();\r
+ cp.insertTranslator(translator);\r
+ Loader cl = new Loader();\r
+ cl.setClassPool(cp);\r
\r
- translator.makeUpdatable("sample.evolve.WebPage");\r
- cl.run("sample.evolve.DemoServer", args);\r
+ translator.makeUpdatable("sample.evolve.WebPage");\r
+ cl.run("sample.evolve.DemoServer", args);\r
}\r
}\r
--- /dev/null
+/*\r
+ * Javassist, a Java-bytecode translator toolkit.\r
+ * Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License. Alternatively, the contents of this file may be used under\r
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ */\r
+\r
+package javassist;\r
+\r
+import java.io.DataOutputStream;\r
+import java.io.IOException;\r
+import java.net.URL;\r
+\r
+/**\r
+ * Abstract root of ClassPool and ClassPoolTail.\r
+ */\r
+abstract class AbsClassPool {\r
+ public abstract String toString();\r
+\r
+ public abstract void recordInvalidClassName(String name);\r
+\r
+ abstract byte[] readSource(String classname)\r
+ throws NotFoundException, IOException, CannotCompileException;\r
+\r
+ abstract boolean write0(String classname, DataOutputStream out,\r
+ boolean callback)\r
+ throws NotFoundException, CannotCompileException, IOException;\r
+\r
+ abstract URL find(String classname);\r
+\r
+ public abstract ClassPath appendSystemPath();\r
+ public abstract ClassPath insertClassPath(ClassPath cp);\r
+ public abstract ClassPath appendClassPath(ClassPath cp);\r
+ public abstract ClassPath insertClassPath(String pathname)\r
+ throws NotFoundException;\r
+ public abstract ClassPath appendClassPath(String pathname)\r
+ throws NotFoundException;\r
+ public abstract void removeClassPath(ClassPath cp);\r
+}\r
* <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.
* @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());
+ }
}
/**
*
* @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;
}
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.
}
/**
- * 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.
/**
* 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
/**
* 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.
*
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())) {
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
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;
*
* @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);
}
/**
}
/**
- * 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.
*
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;
}
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;
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
* 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);
}
}
}
-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();
}
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);
* 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);
* 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;
if (error != null)
throw error;
else
- throw new NotFoundException(classname);
+ return null; // not found
}
/**
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);
= (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);
* 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
*
* @see javassist.CtClass#getClassFile()
*/
-public final class ClassFile
-{
- ConstPool constPool;
- int thisClass;
- int accessFlags;
- int superClass;
- int[] interfaces;
- LinkedList fields;
- LinkedList methods;
- LinkedList attributes;
- AnnotationGroup runtimeInvisible;
- AnnotationGroup runtimeVisible;
-
- String thisclassname; // not JVM-internal name
-
- /**
- * Constructs a class file from a byte stream.
- */
- public ClassFile(DataInputStream in) throws IOException
- {
- read(in);
- }
-
- /**
- * Constructs a class file including no members.
- *
- * @param isInterface true if this is an interface.
- * false if this is a class.
- * @param classname a fully-qualified class name
- * @param superclass a fully-qualified super class name
- */
- public ClassFile(boolean isInterface,
- String classname, String superclass)
- {
- constPool = new ConstPool(classname);
- thisClass = constPool.getThisClassInfo();
- if (isInterface)
- accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE
- | AccessFlag.ABSTRACT;
- else
- accessFlags = AccessFlag.SUPER;
-
- initSuperclass(superclass);
- interfaces = null;
- fields = new LinkedList();
- methods = new LinkedList();
- thisclassname = classname;
-
- attributes = new LinkedList();
- attributes.add(new SourceFileAttribute(constPool,
- getSourcefileName(thisclassname)));
- }
-
- private void initSuperclass(String superclass)
- {
- if (superclass != null)
- superClass = constPool.addClassInfo(superclass);
- else
- superClass = constPool.addClassInfo("java.lang.Object");
- }
-
- private static String getSourcefileName(String qname)
- {
- int index = qname.lastIndexOf('.');
- if (index >= 0)
- qname = qname.substring(index + 1);
-
- return qname + ".java";
- }
-
- /**
- * Returns a constant pool table.
- */
- public ConstPool getConstPool()
- {
- return constPool;
- }
-
- /**
- * Returns true if this is an interface.
- */
- public boolean isInterface()
- {
- return (accessFlags & AccessFlag.INTERFACE) != 0;
- }
-
- /**
- * Returns true if this is a final class or interface.
- */
- public boolean isFinal()
- {
- return (accessFlags & AccessFlag.FINAL) != 0;
- }
-
- /**
- * Returns true if this is an abstract class or an interface.
- */
- public boolean isAbstract()
- {
- return (accessFlags & AccessFlag.ABSTRACT) != 0;
- }
-
- /**
- * Returns access flags.
- *
- * @see javassist.bytecode.AccessFlag
- */
- public int getAccessFlags()
- {
- return accessFlags;
- }
-
- /**
- * Changes access flags.
- *
- * @see javassist.bytecode.AccessFlag
- */
- public void setAccessFlags(int acc)
- {
- accessFlags = acc | AccessFlag.SUPER;
- }
-
- /**
- * Returns the class name.
- */
- public String getName()
- {
- return thisclassname;
- }
-
- /**
- * Sets the class name. This method substitutes the new name
- * for all occurrences of the old class name in the class file.
- */
- public void setName(String name)
- {
- renameClass(thisclassname, name);
- }
-
- /**
- * Returns the super class name.
- */
- public String getSuperclass()
- {
- return constPool.getClassInfo(superClass);
- }
-
- /**
- * Returns the index of the constant pool entry representing
- * the super class.
- */
- public int getSuperclassId()
- {
- return superClass;
- }
-
- /**
- * Sets the super class.
- *
- * <p>This method modifies constructors so that they call
- * constructors declared in the new super class.
- */
- public void setSuperclass(String superclass)
- throws CannotCompileException
- {
- if (superclass == null)
- superclass = "java.lang.Object";
-
- try
- {
- superClass = constPool.addClassInfo(superclass);
- LinkedList list = methods;
- int n = list.size();
- for (int i = 0; i < n; ++i)
- {
- MethodInfo minfo = (MethodInfo) list.get(i);
- minfo.setSuperclass(superclass);
- }
- }
- catch (BadBytecode e)
- {
- throw new CannotCompileException(e);
- }
- }
-
- /**
- * Replaces all occurrences of a class name in the class file.
- *
- * <p>If class X is substituted for class Y in the class file,
- * X and Y must have the same signature. If Y provides a method
- * m(), X must provide it even if X inherits m() from the super class.
- * If this fact is not guaranteed, the bytecode verifier may cause
- * an error.
- *
- * @param oldname the replaced class name
- * @param newname the substituted class name
- */
- public final void renameClass(String oldname, String newname)
- {
- LinkedList list;
- int n;
-
- if (oldname.equals(newname))
- return;
-
- if (oldname.equals(thisclassname))
- thisclassname = newname;
-
- oldname = Descriptor.toJvmName(oldname);
- newname = Descriptor.toJvmName(newname);
- constPool.renameClass(oldname, newname);
-
- list = methods;
- n = list.size();
- for (int i = 0; i < n; ++i)
- {
- MethodInfo minfo = (MethodInfo) list.get(i);
- String desc = minfo.getDescriptor();
- minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
- }
-
- list = fields;
- n = list.size();
- for (int i = 0; i < n; ++i)
- {
- FieldInfo finfo = (FieldInfo) list.get(i);
- String desc = finfo.getDescriptor();
- finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
- }
- }
-
- /**
- * Replaces all occurrences of several class names in the class file.
- *
- * @param classnames specifies which class name is replaced
- * with which new name. Class names must
- * be described with the JVM-internal
- * representation like
- * <code>java/lang/Object</code>.
- *
- * @see #renameClass(String,String)
- */
- public final void renameClass(Map classnames)
- {
- String jvmNewThisName
- = (String) classnames.get(Descriptor.toJvmName(thisclassname));
- if (jvmNewThisName != null)
- thisclassname = Descriptor.toJavaName(jvmNewThisName);
-
- constPool.renameClass(classnames);
-
- LinkedList list = methods;
- int n = list.size();
- for (int i = 0; i < n; ++i)
- {
- MethodInfo minfo = (MethodInfo) list.get(i);
- String desc = minfo.getDescriptor();
- minfo.setDescriptor(Descriptor.rename(desc, classnames));
- }
-
- list = fields;
- n = list.size();
- for (int i = 0; i < n; ++i)
- {
- FieldInfo finfo = (FieldInfo) list.get(i);
- String desc = finfo.getDescriptor();
- finfo.setDescriptor(Descriptor.rename(desc, classnames));
- }
- }
-
- /**
- * Returns the names of the interfaces implemented by the class.
- */
- public String[] getInterfaces()
- {
- if (interfaces == null)
- return new String[0];
- else
- {
- int n = interfaces.length;
- String[] list = new String[n];
- for (int i = 0; i < n; ++i)
- list[i] = constPool.getClassInfo(interfaces[i]);
-
- return list;
- }
- }
-
- /**
- * Sets the interfaces.
- *
- * @param nameList the names of the interfaces.
- */
- public void setInterfaces(String[] nameList)
- {
- if (nameList != null)
- {
- int n = nameList.length;
- interfaces = new int[n];
- for (int i = 0; i < n; ++i)
- interfaces[i] = constPool.addClassInfo(nameList[i]);
- }
- }
-
- /**
- * Appends an interface to the
- * interfaces implemented by the class.
- */
- public void addInterface(String name)
- {
- int info = constPool.addClassInfo(name);
- if (interfaces == null)
- {
- interfaces = new int[1];
- interfaces[0] = info;
- }
- else
- {
- int n = interfaces.length;
- int[] newarray = new int[n + 1];
- System.arraycopy(interfaces, 0, newarray, 0, n);
- newarray[n] = info;
- interfaces = newarray;
- }
- }
-
- /**
- * Returns all the fields declared in the class.
- *
- * @return a list of <code>FieldInfo</code>.
- * @see FieldInfo
- */
- public List getFields()
- {
- return fields;
- }
-
- /**
- * Appends a field to the class.
- */
- public void addField(FieldInfo finfo) throws CannotCompileException
- {
- testExistingField(finfo.getName(), finfo.getDescriptor());
- fields.add(finfo);
- }
-
- private void addField0(FieldInfo finfo)
- {
- fields.add(finfo);
- }
-
- private void testExistingField(String name, String descriptor)
- throws CannotCompileException
- {
- ListIterator it = fields.listIterator(0);
- while (it.hasNext())
- {
- FieldInfo minfo = (FieldInfo) it.next();
- if (minfo.getName().equals(name))
- throw new CannotCompileException("duplicate field: " + name);
- }
- }
-
- /**
- * Returns all the methods declared in the class.
- *
- * @return a list of <code>MethodInfo</code>.
- * @see MethodInfo
- */
- public List getMethods()
- {
- return methods;
- }
-
- /**
- * Returns the method with the specified name. If there are multiple
- * methods with that name, this method returns one of them.
- *
- * @return null if no such a method is found.
- */
- public MethodInfo getMethod(String name)
- {
- LinkedList list = methods;
- int n = list.size();
- for (int i = 0; i < n; ++i)
- {
- MethodInfo minfo = (MethodInfo) list.get(i);
- if (minfo.getName().equals(name))
- return minfo;
- }
-
- return null;
- }
-
- /**
- * Returns a static initializer (class initializer), or null if
- * it does not exist.
- */
- public MethodInfo getStaticInitializer()
- {
- return getMethod(MethodInfo.nameClinit);
- }
-
- /**
- * Appends a method to the class.
- */
- public void addMethod(MethodInfo minfo) throws CannotCompileException
- {
- testExistingMethod(minfo.getName(), minfo.getDescriptor());
- methods.add(minfo);
- }
-
- private void addMethod0(MethodInfo minfo)
- {
- methods.add(minfo);
- }
-
- private void testExistingMethod(String name, String descriptor)
- throws CannotCompileException
- {
- ListIterator it = methods.listIterator(0);
- while (it.hasNext())
- {
- MethodInfo minfo = (MethodInfo) it.next();
- if (minfo.getName().equals(name)
- && Descriptor.eqSignature(minfo.getDescriptor(), descriptor))
- throw new CannotCompileException("duplicate method: " + name);
- }
- }
-
- /**
- * Returns all the attributes.
- *
- * @return a list of <code>AttributeInfo</code> objects.
- * @see AttributeInfo
- */
- public List getAttributes()
- {
- return attributes;
- }
-
- /**
- * 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 the attribute with the specified name.
- *
- * @param name attribute name
- */
- public AttributeInfo getAttribute(String name)
- {
- LinkedList list = attributes;
- int n = list.size();
- for (int i = 0; i < n; ++i)
- {
- AttributeInfo ai = (AttributeInfo) list.get(i);
- if (ai.getName().equals(name))
- return ai;
- }
-
- return null;
- }
-
- /**
- * Appends an attribute. If there is already an attribute with
- * the same name, the new one substitutes for it.
- */
- public void addAttribute(AttributeInfo info)
- {
- AttributeInfo.remove(attributes, info.getName());
- attributes.add(info);
- }
-
- /**
- * Returns the source file containing this class.
- *
- * @return null if this information is not available.
- */
- public String getSourceFile()
- {
- SourceFileAttribute sf
- = (SourceFileAttribute) getAttribute(SourceFileAttribute.tag);
- if (sf == null)
- return null;
- else
- return sf.getFileName();
- }
-
- private void read(DataInputStream in) throws IOException
- {
- int i, n;
- int magic = in.readInt();
- if (magic != 0xCAFEBABE)
- throw new IOException("non class file");
-
- int major = in.readUnsignedShort();
- int minor = in.readUnsignedShort();
- constPool = new ConstPool(in);
- accessFlags = in.readUnsignedShort();
- thisClass = in.readUnsignedShort();
- constPool.setThisClassInfo(thisClass);
- superClass = in.readUnsignedShort();
- n = in.readUnsignedShort();
- if (n == 0)
- interfaces = null;
- else
- {
- interfaces = new int[n];
- for (i = 0; i < n; ++i)
- interfaces[i] = in.readUnsignedShort();
- }
-
- ConstPool cp = constPool;
- n = in.readUnsignedShort();
- fields = new LinkedList();
- for (i = 0; i < n; ++i)
- addField0(new FieldInfo(cp, in));
-
- n = in.readUnsignedShort();
- methods = new LinkedList();
- for (i = 0; i < n; ++i)
- addMethod0(new MethodInfo(cp, in));
-
- attributes = new LinkedList();
- n = in.readUnsignedShort();
- for (i = 0; i < n; ++i)
- addAttribute(AttributeInfo.read(cp, in));
-
- thisclassname = constPool.getClassInfo(thisClass);
- }
-
- /**
- * Writes a class file represened by this object
- * into an output stream.
- */
- public void write(DataOutputStream out) throws IOException
- {
- int i, n;
-
- out.writeInt(0xCAFEBABE); // magic
- out.writeShort(3); // major version
- out.writeShort(45); // minor version
- constPool.write(out); // constant pool
- out.writeShort(accessFlags);
- out.writeShort(thisClass);
- out.writeShort(superClass);
-
- if (interfaces == null)
- n = 0;
- else
- n = interfaces.length;
-
- out.writeShort(n);
- for (i = 0; i < n; ++i)
- out.writeShort(interfaces[i]);
-
- LinkedList list = fields;
- n = list.size();
- out.writeShort(n);
- for (i = 0; i < n; ++i)
- {
- FieldInfo finfo = (FieldInfo) list.get(i);
- finfo.write(out);
- }
-
- list = methods;
- n = list.size();
- out.writeShort(n);
- for (i = 0; i < n; ++i)
- {
- MethodInfo minfo = (MethodInfo) list.get(i);
- minfo.write(out);
- }
-
- out.writeShort(attributes.size());
- AttributeInfo.writeAll(attributes, out);
- }
+public final class ClassFile {
+ ConstPool constPool;
+ int thisClass;
+ int accessFlags;
+ int superClass;
+ int[] interfaces;
+ LinkedList fields;
+ LinkedList methods;
+ LinkedList attributes;
+ AnnotationGroup runtimeInvisible;
+ AnnotationGroup runtimeVisible;
+
+ String thisclassname; // not JVM-internal name
+
+ /**
+ * Constructs a class file from a byte stream.
+ */
+ public ClassFile(DataInputStream in) throws IOException {
+ read(in);
+ }
+
+ /**
+ * Constructs a class file including no members.
+ *
+ * @param isInterface true if this is an interface.
+ * false if this is a class.
+ * @param classname a fully-qualified class name
+ * @param superclass a fully-qualified super class name
+ */
+ public ClassFile(boolean isInterface,
+ String classname, String superclass) {
+ constPool = new ConstPool(classname);
+ thisClass = constPool.getThisClassInfo();
+ if (isInterface)
+ accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE
+ | AccessFlag.ABSTRACT;
+ else
+ accessFlags = AccessFlag.SUPER;
+
+ initSuperclass(superclass);
+ interfaces = null;
+ fields = new LinkedList();
+ methods = new LinkedList();
+ thisclassname = classname;
+
+ attributes = new LinkedList();
+ attributes.add(new SourceFileAttribute(constPool,
+ getSourcefileName(thisclassname)));
+ }
+
+ private void initSuperclass(String superclass) {
+ if (superclass != null)
+ superClass = constPool.addClassInfo(superclass);
+ else
+ superClass = constPool.addClassInfo("java.lang.Object");
+ }
+
+ private static String getSourcefileName(String qname) {
+ int index = qname.lastIndexOf('.');
+ if (index >= 0)
+ qname = qname.substring(index + 1);
+
+ return qname + ".java";
+ }
+
+ /**
+ * Returns a constant pool table.
+ */
+ public ConstPool getConstPool() {
+ return constPool;
+ }
+
+ /**
+ * Returns true if this is an interface.
+ */
+ public boolean isInterface() {
+ return (accessFlags & AccessFlag.INTERFACE) != 0;
+ }
+
+ /**
+ * Returns true if this is a final class or interface.
+ */
+ public boolean isFinal() {
+ return (accessFlags & AccessFlag.FINAL) != 0;
+ }
+
+ /**
+ * Returns true if this is an abstract class or an interface.
+ */
+ public boolean isAbstract() {
+ return (accessFlags & AccessFlag.ABSTRACT) != 0;
+ }
+
+ /**
+ * Returns access flags.
+ *
+ * @see javassist.bytecode.AccessFlag
+ */
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ /**
+ * Changes access flags.
+ *
+ * @see javassist.bytecode.AccessFlag
+ */
+ public void setAccessFlags(int acc) {
+ accessFlags = acc | AccessFlag.SUPER;
+ }
+
+ /**
+ * Returns the class name.
+ */
+ public String getName() {
+ return thisclassname;
+ }
+
+ /**
+ * Sets the class name. This method substitutes the new name
+ * for all occurrences of the old class name in the class file.
+ */
+ public void setName(String name) {
+ renameClass(thisclassname, name);
+ }
+
+ /**
+ * Returns the super class name.
+ */
+ public String getSuperclass() {
+ return constPool.getClassInfo(superClass);
+ }
+
+ /**
+ * Returns the index of the constant pool entry representing
+ * the super class.
+ */
+ public int getSuperclassId() {
+ return superClass;
+ }
+
+ /**
+ * Sets the super class.
+ *
+ * <p>This method modifies constructors so that they call
+ * constructors declared in the new super class.
+ */
+ public void setSuperclass(String superclass)
+ throws CannotCompileException
+ {
+ if (superclass == null)
+ superclass = "java.lang.Object";
+
+ try {
+ superClass = constPool.addClassInfo(superclass);
+ LinkedList list = methods;
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ minfo.setSuperclass(superclass);
+ }
+ }
+ catch (BadBytecode e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ /**
+ * Replaces all occurrences of a class name in the class file.
+ *
+ * <p>If class X is substituted for class Y in the class file,
+ * X and Y must have the same signature. If Y provides a method
+ * m(), X must provide it even if X inherits m() from the super class.
+ * If this fact is not guaranteed, the bytecode verifier may cause
+ * an error.
+ *
+ * @param oldname the replaced class name
+ * @param newname the substituted class name
+ */
+ public final void renameClass(String oldname, String newname) {
+ LinkedList list;
+ int n;
+
+ if (oldname.equals(newname))
+ return;
+
+ if (oldname.equals(thisclassname))
+ thisclassname = newname;
+
+ oldname = Descriptor.toJvmName(oldname);
+ newname = Descriptor.toJvmName(newname);
+ constPool.renameClass(oldname, newname);
+
+ list = methods;
+ n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ String desc = minfo.getDescriptor();
+ minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
+ }
+
+ list = fields;
+ n = list.size();
+ for (int i = 0; i < n; ++i) {
+ FieldInfo finfo = (FieldInfo)list.get(i);
+ String desc = finfo.getDescriptor();
+ finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
+ }
+ }
+
+ /**
+ * Replaces all occurrences of several class names in the class file.
+ *
+ * @param classnames specifies which class name is replaced
+ * with which new name. Class names must
+ * be described with the JVM-internal
+ * representation like
+ * <code>java/lang/Object</code>.
+ *
+ * @see #renameClass(String,String)
+ */
+ public final void renameClass(Map classnames) {
+ String jvmNewThisName
+ = (String)classnames.get(Descriptor.toJvmName(thisclassname));
+ if (jvmNewThisName != null)
+ thisclassname = Descriptor.toJavaName(jvmNewThisName);
+
+ constPool.renameClass(classnames);
+
+ LinkedList list = methods;
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ String desc = minfo.getDescriptor();
+ minfo.setDescriptor(Descriptor.rename(desc, classnames));
+ }
+
+ list = fields;
+ n = list.size();
+ for (int i = 0; i < n; ++i) {
+ FieldInfo finfo = (FieldInfo)list.get(i);
+ String desc = finfo.getDescriptor();
+ finfo.setDescriptor(Descriptor.rename(desc, classnames));
+ }
+ }
+
+ /**
+ * Returns the names of the interfaces implemented by the class.
+ */
+ public String[] getInterfaces() {
+ if (interfaces == null)
+ return new String[0];
+ else {
+ int n = interfaces.length;
+ String[] list = new String[n];
+ for (int i = 0; i < n; ++i)
+ list[i] = constPool.getClassInfo(interfaces[i]);
+
+ return list;
+ }
+ }
+
+ /**
+ * Sets the interfaces.
+ *
+ * @param nameList the names of the interfaces.
+ */
+ public void setInterfaces(String[] nameList) {
+ if (nameList != null) {
+ int n = nameList.length;
+ interfaces = new int[n];
+ for (int i = 0; i < n; ++i)
+ interfaces[i] = constPool.addClassInfo(nameList[i]);
+ }
+ }
+
+ /**
+ * Appends an interface to the
+ * interfaces implemented by the class.
+ */
+ public void addInterface(String name) {
+ int info = constPool.addClassInfo(name);
+ if (interfaces == null) {
+ interfaces = new int[1];
+ interfaces[0] = info;
+ }
+ else {
+ int n = interfaces.length;
+ int[] newarray = new int[n + 1];
+ System.arraycopy(interfaces, 0, newarray, 0, n);
+ newarray[n] = info;
+ interfaces = newarray;
+ }
+ }
+
+ /**
+ * Returns all the fields declared in the class.
+ *
+ * @return a list of <code>FieldInfo</code>.
+ * @see FieldInfo
+ */
+ public List getFields() {
+ return fields;
+ }
+
+ /**
+ * Appends a field to the class.
+ */
+ public void addField(FieldInfo finfo) throws CannotCompileException {
+ testExistingField(finfo.getName(), finfo.getDescriptor());
+ fields.add(finfo);
+ }
+
+ private void addField0(FieldInfo finfo) {
+ fields.add(finfo);
+ }
+
+ private void testExistingField(String name, String descriptor)
+ throws CannotCompileException
+ {
+ ListIterator it = fields.listIterator(0);
+ while (it.hasNext()) {
+ FieldInfo minfo = (FieldInfo)it.next();
+ if (minfo.getName().equals(name))
+ throw new CannotCompileException("duplicate field: " + name);
+ }
+ }
+
+ /**
+ * Returns all the methods declared in the class.
+ *
+ * @return a list of <code>MethodInfo</code>.
+ * @see MethodInfo
+ */
+ public List getMethods() {
+ return methods;
+ }
+
+ /**
+ * Returns the method with the specified name. If there are multiple
+ * methods with that name, this method returns one of them.
+ *
+ * @return null if no such a method is found.
+ */
+ public MethodInfo getMethod(String name) {
+ LinkedList list = methods;
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ if (minfo.getName().equals(name))
+ return minfo;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a static initializer (class initializer), or null if
+ * it does not exist.
+ */
+ public MethodInfo getStaticInitializer() {
+ return getMethod(MethodInfo.nameClinit);
+ }
+
+ /**
+ * Appends a method to the class.
+ */
+ public void addMethod(MethodInfo minfo) throws CannotCompileException {
+ testExistingMethod(minfo.getName(), minfo.getDescriptor());
+ methods.add(minfo);
+ }
+
+ private void addMethod0(MethodInfo minfo) {
+ methods.add(minfo);
+ }
+
+ private void testExistingMethod(String name, String descriptor)
+ throws CannotCompileException
+ {
+ ListIterator it = methods.listIterator(0);
+ while (it.hasNext()) {
+ MethodInfo minfo = (MethodInfo)it.next();
+ if (minfo.getName().equals(name)
+ && Descriptor.eqSignature(minfo.getDescriptor(), descriptor))
+ throw new CannotCompileException("duplicate method: " + name);
+ }
+ }
+
+ /**
+ * Returns all the attributes.
+ *
+ * @return a list of <code>AttributeInfo</code> objects.
+ * @see AttributeInfo
+ */
+ public List getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * 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 the attribute with the specified name.
+ *
+ * @param name attribute name
+ */
+ public AttributeInfo getAttribute(String name) {
+ LinkedList list = attributes;
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ AttributeInfo ai = (AttributeInfo)list.get(i);
+ if (ai.getName().equals(name))
+ return ai;
+ }
+
+ return null;
+ }
+
+ /**
+ * Appends an attribute. If there is already an attribute with
+ * the same name, the new one substitutes for it.
+ */
+ public void addAttribute(AttributeInfo info) {
+ AttributeInfo.remove(attributes, info.getName());
+ attributes.add(info);
+ }
+
+ /**
+ * Returns the source file containing this class.
+ *
+ * @return null if this information is not available.
+ */
+ public String getSourceFile() {
+ SourceFileAttribute sf
+ = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag);
+ if (sf == null)
+ return null;
+ else
+ return sf.getFileName();
+ }
+
+ private void read(DataInputStream in) throws IOException {
+ int i, n;
+ int magic = in.readInt();
+ if (magic != 0xCAFEBABE)
+ throw new IOException("non class file");
+
+ int major = in.readUnsignedShort();
+ int minor = in.readUnsignedShort();
+ constPool = new ConstPool(in);
+ accessFlags = in.readUnsignedShort();
+ thisClass = in.readUnsignedShort();
+ constPool.setThisClassInfo(thisClass);
+ superClass = in.readUnsignedShort();
+ n = in.readUnsignedShort();
+ if (n == 0)
+ interfaces = null;
+ else {
+ interfaces = new int[n];
+ for (i = 0; i < n; ++i)
+ interfaces[i] = in.readUnsignedShort();
+ }
+
+ ConstPool cp = constPool;
+ n = in.readUnsignedShort();
+ fields = new LinkedList();
+ for (i = 0; i < n; ++i)
+ addField0(new FieldInfo(cp, in));
+
+ n = in.readUnsignedShort();
+ methods = new LinkedList();
+ for (i = 0; i < n; ++i)
+ addMethod0(new MethodInfo(cp, in));
+
+ attributes = new LinkedList();
+ n = in.readUnsignedShort();
+ for (i = 0; i < n; ++i)
+ addAttribute(AttributeInfo.read(cp, in));
+
+ thisclassname = constPool.getClassInfo(thisClass);
+ }
+
+ /**
+ * Writes a class file represened by this object
+ * into an output stream.
+ */
+ public void write(DataOutputStream out) throws IOException {
+ int i, n;
+
+ out.writeInt(0xCAFEBABE); // magic
+ out.writeShort(3); // major version
+ out.writeShort(45); // minor version
+ constPool.write(out); // constant pool
+ out.writeShort(accessFlags);
+ out.writeShort(thisClass);
+ out.writeShort(superClass);
+
+ if (interfaces == null)
+ n = 0;
+ else
+ n = interfaces.length;
+
+ out.writeShort(n);
+ for (i = 0; i < n; ++i)
+ out.writeShort(interfaces[i]);
+
+ LinkedList list = fields;
+ n = list.size();
+ out.writeShort(n);
+ for (i = 0; i < n; ++i) {
+ FieldInfo finfo = (FieldInfo)list.get(i);
+ finfo.write(out);
+ }
+
+ list = methods;
+ n = list.size();
+ out.writeShort(n);
+ for (i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ minfo.write(out);
+ }
+
+ out.writeShort(attributes.size());
+ AttributeInfo.writeAll(attributes, out);
+ }
}
*
* @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);
+ }
+ }
}
* @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);
+ }
+ }
}
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);
delegateLoadingOf("javassist.reflect.Loader");
reflection = new Reflection();
- setClassPool(ClassPool.getDefault(reflection));
+ ClassPool pool = ClassPool.getDefault();
+ pool.insertTranslator(reflection);
+ setClassPool(pool);
}
/**
public AppletServer(int port)
throws IOException, NotFoundException, CannotCompileException
{
- this(ClassPool.getDefault(new StubGenerator()), port);
+ this(ClassPool.getDefault(), new StubGenerator(), port);
}
/**
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);
}