]> source.dussan.org Git - javassist.git/commitdiff
changed the stuff related to ClassPool.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 5 Apr 2004 09:24:26 +0000 (09:24 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 5 Apr 2004 09:24:26 +0000 (09:24 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@76 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

16 files changed:
Readme.html
build.xml
sample/Test.java
sample/evolve/DemoLoader.java
src/main/javassist/AbsClassPool.java [new file with mode: 0644]
src/main/javassist/ClassPath.java
src/main/javassist/ClassPool.java
src/main/javassist/ClassPoolTail.java
src/main/javassist/CtClassType.java
src/main/javassist/Translator.java
src/main/javassist/bytecode/ClassFile.java
src/main/javassist/bytecode/FieldInfo.java
src/main/javassist/bytecode/MethodInfo.java
src/main/javassist/reflect/Compiler.java
src/main/javassist/reflect/Loader.java
src/main/javassist/rmi/AppletServer.java

index 3d688faa3be8c8625e854f102f7e20c0bd244509..c5d0b5795188ad60cd31429f62ff7bc45409da73 100644 (file)
@@ -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.
index f5c07ff9b21b22f353428781a1605299c810168f..004bb513d06e63008ff18359cb4c05c9cec793b6 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -1,18 +1,21 @@
 <?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
@@ -61,7 +64,7 @@ to ${build.classes.dir}.</echo>
   </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
@@ -103,8 +106,72 @@ Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
   <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
index 0692943ff738d1525b2cb8d95f407bd31c09a62e..07eeda98cbd6810ad5676c6d08356d8445c4c0d3 100644 (file)
@@ -23,7 +23,7 @@ public class Test {
     }\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
index 5fa950da24676ad114125137ac7e3430fcefe036..ecf45049c399befafb5eb51ac9786541e16d34d8 100644 (file)
@@ -29,12 +29,13 @@ public class DemoLoader {
      * 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
diff --git a/src/main/javassist/AbsClassPool.java b/src/main/javassist/AbsClassPool.java
new file mode 100644 (file)
index 0000000..5425cab
--- /dev/null
@@ -0,0 +1,47 @@
+/*\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
index 948b53b554ca3c2921692fce8db04a2d5f0df5c8..e249272b03d7c0bf02a598e300998b91e8dacd88 100644 (file)
@@ -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.
index 863750a2606f17b138fe3d203dd4254f16ecbfe8..e19915afc720dfa148bb1e12c2eeb093b56531f0 100644 (file)
@@ -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);
     }
 
index 2731ba3d2f50edaddbddbfc770e7e94767a138b9..fb0198036cf794df22c6850f74b358a6ddb5df8c 100644 (file)
@@ -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
     }
 
     /**
index 596ab0b3136b44d05508eb594f40f28b4fc5031b..3b57bd67da87d057b8f041654b0fdc1a7bd13a19 100644 (file)
@@ -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);
index f48e862072bf60502e31f53187dc874746a1c851..57cca039ca77801c56d3ba47858feaa0e9186fc5 100644 (file)
@@ -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
index b156176de7c1de8e28800367bf94d14deae62b5d..9e759b0d58177bf5493b7136242cb850b0603235 100644 (file)
@@ -32,636 +32,584 @@ import javassist.bytecode.annotation.AnnotationGroup;
  *
  * @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);
+    }
 }
index 6bb937e282c33cef3235534124cd708f18cdac48..6ddfcebd05f1c3818f87bb09c71f9222d2c8db93 100644 (file)
@@ -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);
+        }
+    }
 }
index ff887ff40044d8232a03da083e0699bfeaed1599..ffe42438963a43cbc2ab5e6cbf11ade6a860b2ad 100644 (file)
@@ -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>&lt;init&gt</code>.
-    */
-   public static final String nameInit = "<init>";
-
-   /**
-    * The name of class initializer (static initializer):
-    * <code>&lt;clinit&gt</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 (&gt;= 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>&lt;init&gt</code>.
+     */
+    public static final String nameInit = "<init>";
+
+    /**
+     * The name of class initializer (static initializer):
+     * <code>&lt;clinit&gt</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 (&gt;= 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);
+        }
+    }
 }
index 661908ae529c8a60277bb31943029f5a72114787..c5650bd1ef10725038ac58da882999a288afa660 100644 (file)
@@ -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);
index 62b52932371397d01059f0384fc33721510bf98b..ee9b30046cecef133f710dc99b081a2f4674b18c 100644 (file)
@@ -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);
     }
 
     /**
index aab9dbcca852956180cda9b07bc058b89a0ff801..a848c5c4f06397f77a08489306a2d3917965987b 100644 (file)
@@ -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);
     }