]> source.dussan.org Git - javassist.git/commitdiff
* additional methods to AnnotationsAttribute to support adding
authorpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Tue, 14 Sep 2004 04:17:29 +0000 (04:17 +0000)
committerpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Tue, 14 Sep 2004 04:17:29 +0000 (04:17 +0000)
* turn off pruning.
* move toClass back to ClassPool

git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@137 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/ClassPool.java
src/main/javassist/CtClass.java
src/main/javassist/CtClassType.java
src/main/javassist/bytecode/AnnotationsAttribute.java
src/main/javassist/bytecode/MethodInfo.java
src/main/javassist/bytecode/annotation/ClassMemberValue.java

index a75dec943bbf7788fe9bebacd4b4f27627515e0b..b0a2066c1bcb82207122f1e20e652e7db88fc41e 100644 (file)
 
 package javassist;
 
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.URL;
 import java.util.Hashtable;
 
@@ -27,9 +31,9 @@ import java.util.Hashtable;
  * to find a class file and then it creates a <code>CtClass</code> object
  * representing that class file.  The created object is returned to the
  * caller.
- *
+ * <p/>
  * <p><b>Memory consumption memo:</b>
- *
+ * <p/>
  * <p><code>ClassPool</code> objects hold all the <code>CtClass</code>es
  * that have been created so that the consistency among modified classes
  * can be guaranteed.  Thus if a large number of <code>CtClass</code>es
@@ -39,621 +43,723 @@ import java.util.Hashtable;
  * Note that <code>getDefault()</code> is a singleton factory.
  * Otherwise, <code>detach()</code> in <code>CtClass</code> should be used
  * to avoid huge memory consumption.
- *
+ * <p/>
  * <p><b><code>ClassPool</code> hierarchy:</b>
- *
+ * <p/>
  * <p><code>ClassPool</code>s can make a parent-child hierarchy as
  * <code>java.lang.ClassLoader</code>s.  If a <code>ClassPool</code> has
  * a parent pool, <code>get()</code> first asks the parent pool to find
  * a class file.  Only if the parent could not find the class file,
  * <code>get()</code> searches the <code>ClassPath</code>s of
  * the child <code>ClassPool</code>.  This search order is reversed if
- * <code>ClassPath.childFirstLookup</code> is <code>true</code>. 
+ * <code>ClassPath.childFirstLookup</code> is <code>true</code>.
  *
  * @see javassist.CtClass
  * @see javassist.ClassPath
  */
-public class ClassPool {
-
-    /**
-     * Determines the search order.
-     *
-     * <p>If this field is true, <code>get()</code> first searches the
-     * class path associated to this <code>ClassPool</code> and then
-     * the class path associated with the parent <code>ClassPool</code>.
-     * Otherwise, the class path associated with the parent is searched
-     * first.
-     *
-     * <p>The default value is false.
-     */
-    public boolean childFirstLookup = false;
-
-    protected ClassPoolTail source;
-    protected ClassPool parent;
-    protected Hashtable classes;        // should be synchronous
-
-    /**
-     * Table of registered cflow variables.
-     */
-    private Hashtable cflow = null;     // should be synchronous.
-
-    private static final int INIT_HASH_SIZE = 191; 
-
-    /**
-     * Creates a root class pool.  No parent class pool is specified.
-     *
-     */
-    public ClassPool() {
-        this(null);
-    }
-
-    /**
-     * Creates a class pool.
-     *
-     * @param parent    the parent of this class pool.  If this is a root
-     *                  class pool, this parameter must be <code>null</code>.
-     * @see javassist.ClassPool#getDefault()
-     */
-    public ClassPool(ClassPool parent) {
-        this.classes = new Hashtable(INIT_HASH_SIZE);
-        this.source = new ClassPoolTail();
-        this.parent = parent;
-        if (parent == null) {
-            CtClass[] pt = CtClass.primitiveTypes;
-            for (int i = 0; i < pt.length; ++i)
-                classes.put(pt[i].getName(), pt[i]);
-        }
-
-        this.cflow = null;
-    }
-
-    /**
-     * Returns the default class pool.
-     * The returned object is always identical since this method is
-     * a singleton factory.
-     *
-     * <p>The default class pool searches the system search path,
-     * which usually includes the platform library, extension
-     * libraries, and the search path specified by the
-     * <code>-classpath</code> option or the <code>CLASSPATH</code>
-     * environment variable.
-     *
-     * <p>When this method is called for the first time, the default
-     * class pool is created with the following code snippet:
-     *
-     * <ul><code>ClassPool cp = new ClassPool();
-     * cp.appendSystemPath();
-     * </code></ul>
-     *
-     * <p>If the default class pool cannot find any class files,
-     * try <code>ClassClassPath</code> and <code>LoaderClassPath</code>.
-     *
-     * @see ClassClassPath
-     * @see LoaderClassPath
-     */
-    public static synchronized ClassPool getDefault() {
-        if (defaultPool == null) {
-            defaultPool = new ClassPool(null);
-            defaultPool.appendSystemPath();
-        }
-
-        return defaultPool;
-    }
-
-    private static ClassPool defaultPool = null;
-
-    /**
-     * Provide a hook so that subclasses can do their own
-     * caching of classes.
-     *
-     * @see #cacheCtClass(String,CtClass)
-     * @see #removeCached(String)
-     */
-    protected CtClass getCached(String classname) {
-        return (CtClass)classes.get(classname); 
-    }
-
-    /**
-     * Provides a hook so that subclasses can do their own
-     * caching of classes.
-     *
-     * @see #getCached(String)
-     * @see #removeCached(String,CtClass)
-     */
-    protected void cacheCtClass(String classname, CtClass c) {
-        classes.put(classname, c);
-    }
-
-    /**
-     * Provide a hook so that subclasses can do their own
-     * caching of classes.
-     *
-     * @see #getCached(String)
-     * @see #cacheCtClass(String,CtClass)
-     */
-    protected CtClass removeCached(String classname) {
-        return (CtClass)classes.remove(classname);
-    }
-
-    /**
-     * Returns the class search path.
-     */
-    public String toString() {
-        return source.toString();
-    }
-
-    /**
-     * 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.
-     * Note that searching the class path takes relatively long time.
-     *
-     * @param name          a class name (separeted by dot).
-     */
-    public void recordInvalidClassName(String name) {
-        source.recordInvalidClassName(name);
-    }
-
-    /**
-     * Records the <code>$cflow</code> variable for the field specified
-     * by <code>cname</code> and <code>fname</code>.
-     *
-     * @param name      variable name
-     * @param cname     class name
-     * @param fname     field name
-     */
-    void recordCflow(String name, String cname, String fname) {
-        if (cflow == null)
-            cflow = new Hashtable();
-
-        cflow.put(name, new Object[] { cname, fname });
-    }
-
-    /**
-     * Undocumented method.  Do not use; internal-use only.
-     * 
-     * @param name      the name of <code>$cflow</code> variable
-     */
-    public Object[] lookupCflow(String name) {
-        if (cflow == null)
-            cflow = new Hashtable();
-
-        return (Object[])cflow.get(name);
-    }
-
-   /**
-     * Reads a class file and constructs a <code>CtClass</code>
-     * object with a new name.
-     * This method is useful if you want to generate a new class as a copy
-     * of another class (except the class name).  For example,
-     *
-     * <ul><pre>
-     * getAndRename("Point", "Pair")
-     * </pre></ul>
-     *
-     * returns a <code>CtClass</code> object representing <code>Pair</code>
-     * class.  The definition of <code>Pair</code> is the same as that of
-     * <code>Point</code> class except the class name since <code>Pair</code>
-     * is defined by reading <code>Point.class</code>.
-     *
-     * @param orgName   the original (fully-qualified) class name
-     * @param newName   the new class name
-     */
-    public CtClass getAndRename(String orgName, String newName)
-        throws NotFoundException
-    {
-        CtClass clazz = get0(orgName, false);
-        if (clazz instanceof CtClassType)
-            ((CtClassType)clazz).setClassPool(this);
-
-        clazz.setName(newName);         // indirectly calls
-                                        // classNameChanged() in this class
-        return clazz;
-    }
-
-    /*
-     * This method is invoked by CtClassType.setName().  It removes a
-     * CtClass object from the hash table and inserts it with the new
-     * name.  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);  // see getAndRename().
-
-        String newName = clazz.getName();
-        checkNotFrozen(newName);
-        cacheCtClass(newName, clazz);
-    }
-
-    /**
-     * Reads a class file from the source and returns a reference
-     * to the <code>CtClass</code>
-     * object representing that class file.  If that class file has been
-     * already read, this method returns a reference to the
-     * <code>CtClass</code> created when that class file was read at the
-     * first time.
-     *
-     * <p>If <code>classname</code> ends with "[]", then this method
-     * returns a <code>CtClass</code> object for that array type.
-     *
-     * <p>To obtain an inner class, use "$" instead of "." for separating
-     * the enclosing class name and the inner class name.
-     *
-     * @param classname         a fully-qualified class name.
-     */
-    public CtClass get(String classname) throws NotFoundException {
-        CtClass clazz;
-        if (classname == null)
-            clazz = null;
-        else
-            clazz = get0(classname, true);
-
-        if (clazz == null)
-            throw new NotFoundException(classname);
-        else {
-            clazz.incGetCounter();
-            return clazz;
-        }
-    }
-
-    /**
-     * @param useCache  false if the cached CtClass must be ignored.
-     * @param searchParent  false if the parent class pool is not searched.
-     * @return null     if the class could not be found.
-     */
-    protected synchronized CtClass get0(String classname, boolean useCache)
-        throws NotFoundException
-    {
-        CtClass clazz = null;
-        if (useCache) {
-            clazz = getCached(classname);
-            if (clazz != null)
-                return clazz;
-        }
+public class ClassPool
+{
 
-        if (!childFirstLookup && parent != null) {
-            clazz = parent.get0(classname, useCache);
-            if (clazz != null)
-                return clazz;
-        }
+   /**
+    * Determines the search order.
+    * <p/>
+    * <p>If this field is true, <code>get()</code> first searches the
+    * class path associated to this <code>ClassPool</code> and then
+    * the class path associated with the parent <code>ClassPool</code>.
+    * Otherwise, the class path associated with the parent is searched
+    * first.
+    * <p/>
+    * <p>The default value is false.
+    */
+   public boolean childFirstLookup = false;
+
+   protected ClassPoolTail source;
+   protected ClassPool parent;
+   protected Hashtable classes;        // should be synchronous
 
-        clazz = createCtClass(classname, useCache);
-        if (clazz != null) {
-            if (useCache)
-                cacheCtClass(classname, clazz);
+   /**
+    * Table of registered cflow variables.
+    */
+   private Hashtable cflow = null;     // should be synchronous.
 
+   private static final int INIT_HASH_SIZE = 191;
+
+   /**
+    * Creates a root class pool.  No parent class pool is specified.
+    */
+   public ClassPool()
+   {
+      this(null);
+   }
+
+   /**
+    * Creates a class pool.
+    *
+    * @param parent the parent of this class pool.  If this is a root
+    *               class pool, this parameter must be <code>null</code>.
+    * @see javassist.ClassPool#getDefault()
+    */
+   public ClassPool(ClassPool parent)
+   {
+      this.classes = new Hashtable(INIT_HASH_SIZE);
+      this.source = new ClassPoolTail();
+      this.parent = parent;
+      if (parent == null)
+      {
+         CtClass[] pt = CtClass.primitiveTypes;
+         for (int i = 0; i < pt.length; ++i)
+            classes.put(pt[i].getName(), pt[i]);
+      }
+
+      this.cflow = null;
+   }
+
+   /**
+    * Returns the default class pool.
+    * The returned object is always identical since this method is
+    * a singleton factory.
+    * <p/>
+    * <p>The default class pool searches the system search path,
+    * which usually includes the platform library, extension
+    * libraries, and the search path specified by the
+    * <code>-classpath</code> option or the <code>CLASSPATH</code>
+    * environment variable.
+    * <p/>
+    * <p>When this method is called for the first time, the default
+    * class pool is created with the following code snippet:
+    * <p/>
+    * <ul><code>ClassPool cp = new ClassPool();
+    * cp.appendSystemPath();
+    * </code></ul>
+    * <p/>
+    * <p>If the default class pool cannot find any class files,
+    * try <code>ClassClassPath</code> and <code>LoaderClassPath</code>.
+    *
+    * @see ClassClassPath
+    * @see LoaderClassPath
+    */
+   public static synchronized ClassPool getDefault()
+   {
+      if (defaultPool == null)
+      {
+         defaultPool = new ClassPool(null);
+         defaultPool.appendSystemPath();
+      }
+
+      return defaultPool;
+   }
+
+   private static ClassPool defaultPool = null;
+
+   /**
+    * Provide a hook so that subclasses can do their own
+    * caching of classes.
+    *
+    * @see #cacheCtClass(String,CtClass)
+    * @see #removeCached(String)
+    */
+   protected CtClass getCached(String classname)
+   {
+      return (CtClass) classes.get(classname);
+   }
+
+   /**
+    * Provides a hook so that subclasses can do their own
+    * caching of classes.
+    *
+    * @see #getCached(String)
+    * @see #removeCached(String,CtClass)
+    */
+   protected void cacheCtClass(String classname, CtClass c)
+   {
+      classes.put(classname, c);
+   }
+
+   /**
+    * Provide a hook so that subclasses can do their own
+    * caching of classes.
+    *
+    * @see #getCached(String)
+    * @see #cacheCtClass(String,CtClass)
+    */
+   protected CtClass removeCached(String classname)
+   {
+      return (CtClass) classes.remove(classname);
+   }
+
+   /**
+    * Returns the class search path.
+    */
+   public String toString()
+   {
+      return source.toString();
+   }
+
+   /**
+    * 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.
+    * Note that searching the class path takes relatively long time.
+    *
+    * @param name a class name (separeted by dot).
+    */
+   public void recordInvalidClassName(String name)
+   {
+      source.recordInvalidClassName(name);
+   }
+
+   /**
+    * Records the <code>$cflow</code> variable for the field specified
+    * by <code>cname</code> and <code>fname</code>.
+    *
+    * @param name  variable name
+    * @param cname class name
+    * @param fname field name
+    */
+   void recordCflow(String name, String cname, String fname)
+   {
+      if (cflow == null)
+         cflow = new Hashtable();
+
+      cflow.put(name, new Object[]{cname, fname});
+   }
+
+   /**
+    * Undocumented method.  Do not use; internal-use only.
+    *
+    * @param name the name of <code>$cflow</code> variable
+    */
+   public Object[] lookupCflow(String name)
+   {
+      if (cflow == null)
+         cflow = new Hashtable();
+
+      return (Object[]) cflow.get(name);
+   }
+
+   /**
+    * Reads a class file and constructs a <code>CtClass</code>
+    * object with a new name.
+    * This method is useful if you want to generate a new class as a copy
+    * of another class (except the class name).  For example,
+    * <p/>
+    * <ul><pre>
+    * getAndRename("Point", "Pair")
+    * </pre></ul>
+    * <p/>
+    * returns a <code>CtClass</code> object representing <code>Pair</code>
+    * class.  The definition of <code>Pair</code> is the same as that of
+    * <code>Point</code> class except the class name since <code>Pair</code>
+    * is defined by reading <code>Point.class</code>.
+    *
+    * @param orgName the original (fully-qualified) class name
+    * @param newName the new class name
+    */
+   public CtClass getAndRename(String orgName, String newName)
+           throws NotFoundException
+   {
+      CtClass clazz = get0(orgName, false);
+      if (clazz instanceof CtClassType)
+         ((CtClassType) clazz).setClassPool(this);
+
+      clazz.setName(newName);         // indirectly calls
+      // classNameChanged() in this class
+      return clazz;
+   }
+
+   /*
+    * This method is invoked by CtClassType.setName().  It removes a
+    * CtClass object from the hash table and inserts it with the new
+    * name.  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);  // see getAndRename().
+
+      String newName = clazz.getName();
+      checkNotFrozen(newName);
+      cacheCtClass(newName, clazz);
+   }
+
+   /**
+    * Reads a class file from the source and returns a reference
+    * to the <code>CtClass</code>
+    * object representing that class file.  If that class file has been
+    * already read, this method returns a reference to the
+    * <code>CtClass</code> created when that class file was read at the
+    * first time.
+    * <p/>
+    * <p>If <code>classname</code> ends with "[]", then this method
+    * returns a <code>CtClass</code> object for that array type.
+    * <p/>
+    * <p>To obtain an inner class, use "$" instead of "." for separating
+    * the enclosing class name and the inner class name.
+    *
+    * @param classname a fully-qualified class name.
+    */
+   public CtClass get(String classname) throws NotFoundException
+   {
+      CtClass clazz;
+      if (classname == null)
+         clazz = null;
+      else
+         clazz = get0(classname, true);
+
+      if (clazz == null)
+         throw new NotFoundException(classname);
+      else
+      {
+         clazz.incGetCounter();
+         return clazz;
+      }
+   }
+
+   /**
+    * @param useCache     false if the cached CtClass must be ignored.
+    * @param searchParent false if the parent class pool is not searched.
+    * @return null     if the class could not be found.
+    */
+   protected synchronized CtClass get0(String classname, boolean useCache)
+           throws NotFoundException
+   {
+      CtClass clazz = null;
+      if (useCache)
+      {
+         clazz = getCached(classname);
+         if (clazz != null)
             return clazz;
-        }
-
-        if (childFirstLookup && parent != null)
-            clazz = parent.get0(classname, useCache);
-
-        return clazz;
-    }
-
-    /**
-     * Creates a CtClass object representing the specified class.
-     * It first examines whether or not the corresponding class
-     * file exists.  If yes, it creates a CtClass object.
-     *
-     * @return null if the class file could not be found.
-     */
-    protected CtClass createCtClass(String classname, boolean useCache) {
-        if (classname.endsWith("[]")) {
-            String base = classname.substring(0, classname.indexOf('['));
-            if ((!useCache || 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);
-    }
-
-    /**
-     * Searches the class path to obtain the URL of the class file
-     * specified by classname.  It is also used to determine whether
-     * the class file exists.
-     *
-     * @param classname     a fully-qualified class name.
-     * @return null if the class file could not be found.
-     * @see CtClass#getURL()
-     */
-    public URL find(String classname) {
-        return source.find(classname);
-    }
-
-    /*
-     * 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) throws RuntimeException {
-        CtClass clazz = getCached(classname);
-        if (clazz == null) {
-            if (!childFirstLookup && parent != null) {
-                try {
-                    clazz = parent.get0(classname, true);
-                }
-                catch (NotFoundException e) {}
-                if (clazz != null)
-                    throw new RuntimeException(classname
-                            + " is in a parent ClassPool.  Use the parent.");
-            }
-        }
-        else
-            if (clazz.isFrozen())
-                throw new RuntimeException(classname +
-                                       ": frozen class (cannot edit)");
-    }
-
-    /* for CtClassType.getClassFile2().  Don't delegate to the parent.
-     */
-    InputStream openClassfile(String classname)
-        throws NotFoundException
-    {
-        return source.openClassfile(classname);
-    }
-
-    void writeClassfile(String classname, OutputStream out)
-        throws NotFoundException, IOException, CannotCompileException
-    {
-        source.writeClassfile(classname, out);
-    }
-
-    /**
-     * Reads class files from the source and returns an array of
-     * <code>CtClass</code>
-     * objects representing those class files.
-     *
-     * <p>If an element of <code>classnames</code> ends with "[]",
-     * then this method
-     * returns a <code>CtClass</code> object for that array type.
-     *
-     * @param classnames        an array of fully-qualified class name.
-     */
-    public CtClass[] get(String[] classnames) throws NotFoundException {
-        if (classnames == null)
-            return new CtClass[0];
-
-        int num = classnames.length;
-        CtClass[] result = new CtClass[num];
-        for (int i = 0; i < num; ++i)
-            result[i] = get(classnames[i]);
-
-        return result;
-    }
-
-    /**
-     * Reads a class file and obtains a compile-time method.
-     *
-     * @param classname         the class name
-     * @param methodname        the method name
-     *
-     * @see CtClass#getDeclaredMethod(String)
-     */
-    public CtMethod getMethod(String classname, String methodname)
-        throws NotFoundException
-    {
-        CtClass c = get(classname);
-        return c.getDeclaredMethod(methodname);
-    }
-
-    /**
-     * 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.
-     *
-     * <p>This method is used for creating a <code>CtClass</code> object
-     * directly from a class file.  The qualified class name is obtained
-     * from the class file; you do not have to explicitly give the name.
-     *
-     * @param classfile         class file.
-     * @exception RuntimeException      if there is a frozen class with the
-     *                                  the same name.
-     * @see javassist.ByteArrayClassPath
-     */
-    public CtClass makeClass(InputStream classfile)
-        throws IOException, RuntimeException
-    {
-        classfile = new BufferedInputStream(classfile);
-        CtClass clazz = new CtClassType(classfile, this);
-        clazz.checkModify();
-        String classname = clazz.getName();
-        checkNotFrozen(classname);
-        cacheCtClass(classname, clazz);
-        return clazz;
-    }
-
-    /**
-     * Creates a new public class.
-     * If there already exists a class with the same name, the new class
-     * overwrites that previous class.
-     *
-     * @param classname         a fully-qualified class name.
-     * @exception RuntimeException      if the existing class is frozen.
-     */
-    public CtClass makeClass(String classname) throws RuntimeException {
-        return makeClass(classname, null);
-    }
-
-    /**
-     * Creates a new public class.
-     * If there already exists a class/interface with the same name,
-     * the new class overwrites that previous class.
-     *
-     * @param classname         a fully-qualified class name.
-     * @param superclass        the super class.
-     * @exception RuntimeException      if the existing class is frozen.
-     */
-    public synchronized CtClass makeClass(String classname, CtClass superclass)
-        throws RuntimeException
-    {
-        checkNotFrozen(classname);
-        CtClass clazz = new CtNewClass(classname, this, false, superclass);
-        cacheCtClass(classname, clazz);
-        return clazz;
-    }
-
-    /**
-     * Creates a new nested class.
-     * This method is called by CtClassType.makeNestedClass().
-     *
-     * @param classname     a fully-qualified class name.
-     * @return      the nested class.
-     */
-    synchronized CtClass makeNestedClass(String classname) {
-        checkNotFrozen(classname);
-        CtClass clazz = new CtNewNestedClass(classname, this, false, null);
-        cacheCtClass(classname, clazz);
-        return clazz;
-    }
-
-    /**
-     * Creates a new public interface.
-     * If there already exists a class/interface with the same name,
-     * the new interface overwrites that previous one.
-     *
-     * @param name              a fully-qualified interface name.
-     * @exception RuntimeException      if the existing interface is frozen.
-     */
-    public CtClass makeInterface(String name) throws RuntimeException {
-        return makeInterface(name, null);
-    }
-
-    /**
-     * Creates a new public interface.
-     * If there already exists a class/interface with the same name,
-     * the new interface overwrites that previous one.
-     *
-     * @param name              a fully-qualified interface name.
-     * @param superclass        the super interface.
-     * @exception RuntimeException      if the existing interface is frozen.
-     */
-    public synchronized CtClass makeInterface(String name, CtClass superclass)
-        throws RuntimeException
-    {
-        checkNotFrozen(name);
-        CtClass clazz = new CtNewClass(name, this, true, superclass);
-        cacheCtClass(name, clazz);
-        return clazz;
-    }
-
-    /**
-     * Appends the system search path to the end of the
-     * search path.  The system search path
-     * usually includes the platform library, extension
-     * libraries, and the search path specified by the
-     * <code>-classpath</code> option or the <code>CLASSPATH</code>
-     * environment variable.
-     *
-     * @return the appended class path.
-     */
-    public ClassPath appendSystemPath() {
-        return source.appendSystemPath();
-    }
-
-    /**
-     * Insert a <code>ClassPath</code> object at the head of the
-     * search path.
-     *
-     * @return the inserted class path.
-     *
-     * @see javassist.ClassPath
-     * @see javassist.URLClassPath
-     * @see javassist.ByteArrayClassPath
-     */
-    public ClassPath insertClassPath(ClassPath cp) {
-        return source.insertClassPath(cp);
-    }
-
-    /**
-     * Appends a <code>ClassPath</code> object to the end of the
-     * search path.
-     *
-     * @return the appended class path.
-     *
-     * @see javassist.ClassPath
-     * @see javassist.URLClassPath
-     * @see javassist.ByteArrayClassPath
-     */
-    public ClassPath appendClassPath(ClassPath cp) {
-        return source.appendClassPath(cp);
-    }
-
-    /**
-     * Inserts a directory or a jar (or zip) file at the head of the
-     * search path.
-     *
-     * @param pathname  the path name of the directory or jar file.
-     *                  It must not end with a path separator ("/").
-     * @return          the inserted class path.
-     * @exception NotFoundException     if the jar file is not found.
-     */
-    public ClassPath insertClassPath(String pathname)
-        throws NotFoundException
-    {
-        return source.insertClassPath(pathname);
-    }
-
-    /**
-     * Appends a directory or a jar (or zip) file to the end of the
-     * search path.
-     *
-     * @param pathname  the path name of the directory or jar file.
-     *                  It must not end with a path separator ("/").
-     * @return          the appended class path.
-     * @exception NotFoundException     if the jar file is not found.
-     */
-    public ClassPath appendClassPath(String pathname)
-        throws NotFoundException
-    {
-        return source.appendClassPath(pathname);
-    }
-
-    /**
-     * Detatches the <code>ClassPath</code> object from the search path.
-     * The detached <code>ClassPath</code> object cannot be added
-     * to the pathagain.
-     */
-    public void removeClassPath(ClassPath cp) {
-        source.removeClassPath(cp);
-    }
-
-    /**
-     * Appends directories and jar files for search.
-     *
-     * <p>The elements of the given path list must be separated by colons
-     * in Unix or semi-colons in Windows.
-     *
-     * @param pathlist          a (semi)colon-separated list of
-     *                          the path names of directories and jar files.
-     *                          The directory name must not end with a path
-     *                          separator ("/").
-     *
-     * @exception NotFoundException     if a jar file is not found.
-     */
-    public void appendPathList(String pathlist) throws NotFoundException {
-        char sep = File.pathSeparatorChar;
-        int i = 0;
-        for (;;) {
-            int j = pathlist.indexOf(sep, i);
-            if (j < 0) {
-                appendClassPath(pathlist.substring(i));
-                break;
+      }
+
+      if (!childFirstLookup && parent != null)
+      {
+         clazz = parent.get0(classname, useCache);
+         if (clazz != null)
+            return clazz;
+      }
+
+      clazz = createCtClass(classname, useCache);
+      if (clazz != null)
+      {
+         if (useCache)
+            cacheCtClass(classname, clazz);
+
+         return clazz;
+      }
+
+      if (childFirstLookup && parent != null)
+         clazz = parent.get0(classname, useCache);
+
+      return clazz;
+   }
+
+   /**
+    * Creates a CtClass object representing the specified class.
+    * It first examines whether or not the corresponding class
+    * file exists.  If yes, it creates a CtClass object.
+    *
+    * @return null if the class file could not be found.
+    */
+   protected CtClass createCtClass(String classname, boolean useCache)
+   {
+      if (classname.endsWith("[]"))
+      {
+         String base = classname.substring(0, classname.indexOf('['));
+         if ((!useCache || 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);
+   }
+
+   /**
+    * Searches the class path to obtain the URL of the class file
+    * specified by classname.  It is also used to determine whether
+    * the class file exists.
+    *
+    * @param classname a fully-qualified class name.
+    * @return null if the class file could not be found.
+    * @see CtClass#getURL()
+    */
+   public URL find(String classname)
+   {
+      return source.find(classname);
+   }
+
+   /*
+    * 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) throws RuntimeException
+   {
+      CtClass clazz = getCached(classname);
+      if (clazz == null)
+      {
+         if (!childFirstLookup && parent != null)
+         {
+            try
+            {
+               clazz = parent.get0(classname, true);
             }
-            else {
-                appendClassPath(pathlist.substring(i, j));
-                i = j + 1;
+            catch (NotFoundException e)
+            {
             }
-        }
-    }
+            if (clazz != null)
+               throw new RuntimeException(classname
+                       + " is in a parent ClassPool.  Use the parent.");
+         }
+      }
+      else if (clazz.isFrozen())
+         throw new RuntimeException(classname +
+                 ": frozen class (cannot edit)");
+   }
+
+   /* for CtClassType.getClassFile2().  Don't delegate to the parent.
+    */
+   InputStream openClassfile(String classname)
+           throws NotFoundException
+   {
+      return source.openClassfile(classname);
+   }
+
+   void writeClassfile(String classname, OutputStream out)
+           throws NotFoundException, IOException, CannotCompileException
+   {
+      source.writeClassfile(classname, out);
+   }
+
+   /**
+    * Reads class files from the source and returns an array of
+    * <code>CtClass</code>
+    * objects representing those class files.
+    * <p/>
+    * <p>If an element of <code>classnames</code> ends with "[]",
+    * then this method
+    * returns a <code>CtClass</code> object for that array type.
+    *
+    * @param classnames an array of fully-qualified class name.
+    */
+   public CtClass[] get(String[] classnames) throws NotFoundException
+   {
+      if (classnames == null)
+         return new CtClass[0];
+
+      int num = classnames.length;
+      CtClass[] result = new CtClass[num];
+      for (int i = 0; i < num; ++i)
+         result[i] = get(classnames[i]);
+
+      return result;
+   }
+
+   /**
+    * Reads a class file and obtains a compile-time method.
+    *
+    * @param classname  the class name
+    * @param methodname the method name
+    * @see CtClass#getDeclaredMethod(String)
+    */
+   public CtMethod getMethod(String classname, String methodname)
+           throws NotFoundException
+   {
+      CtClass c = get(classname);
+      return c.getDeclaredMethod(methodname);
+   }
+
+   /**
+    * 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.
+    * <p/>
+    * <p>This method is used for creating a <code>CtClass</code> object
+    * directly from a class file.  The qualified class name is obtained
+    * from the class file; you do not have to explicitly give the name.
+    *
+    * @param classfile class file.
+    * @throws RuntimeException if there is a frozen class with the
+    *                          the same name.
+    * @see javassist.ByteArrayClassPath
+    */
+   public CtClass makeClass(InputStream classfile)
+           throws IOException, RuntimeException
+   {
+      classfile = new BufferedInputStream(classfile);
+      CtClass clazz = new CtClassType(classfile, this);
+      clazz.checkModify();
+      String classname = clazz.getName();
+      checkNotFrozen(classname);
+      cacheCtClass(classname, clazz);
+      return clazz;
+   }
+
+   /**
+    * Creates a new public class.
+    * If there already exists a class with the same name, the new class
+    * overwrites that previous class.
+    *
+    * @param classname a fully-qualified class name.
+    * @throws RuntimeException if the existing class is frozen.
+    */
+   public CtClass makeClass(String classname) throws RuntimeException
+   {
+      return makeClass(classname, null);
+   }
+
+   /**
+    * Creates a new public class.
+    * If there already exists a class/interface with the same name,
+    * the new class overwrites that previous class.
+    *
+    * @param classname  a fully-qualified class name.
+    * @param superclass the super class.
+    * @throws RuntimeException if the existing class is frozen.
+    */
+   public synchronized CtClass makeClass(String classname, CtClass superclass)
+           throws RuntimeException
+   {
+      checkNotFrozen(classname);
+      CtClass clazz = new CtNewClass(classname, this, false, superclass);
+      cacheCtClass(classname, clazz);
+      return clazz;
+   }
+
+   /**
+    * Creates a new nested class.
+    * This method is called by CtClassType.makeNestedClass().
+    *
+    * @param classname a fully-qualified class name.
+    * @return the nested class.
+    */
+   synchronized CtClass makeNestedClass(String classname)
+   {
+      checkNotFrozen(classname);
+      CtClass clazz = new CtNewNestedClass(classname, this, false, null);
+      cacheCtClass(classname, clazz);
+      return clazz;
+   }
+
+   /**
+    * Creates a new public interface.
+    * If there already exists a class/interface with the same name,
+    * the new interface overwrites that previous one.
+    *
+    * @param name a fully-qualified interface name.
+    * @throws RuntimeException if the existing interface is frozen.
+    */
+   public CtClass makeInterface(String name) throws RuntimeException
+   {
+      return makeInterface(name, null);
+   }
+
+   /**
+    * Creates a new public interface.
+    * If there already exists a class/interface with the same name,
+    * the new interface overwrites that previous one.
+    *
+    * @param name       a fully-qualified interface name.
+    * @param superclass the super interface.
+    * @throws RuntimeException if the existing interface is frozen.
+    */
+   public synchronized CtClass makeInterface(String name, CtClass superclass)
+           throws RuntimeException
+   {
+      checkNotFrozen(name);
+      CtClass clazz = new CtNewClass(name, this, true, superclass);
+      cacheCtClass(name, clazz);
+      return clazz;
+   }
+
+   /**
+    * Appends the system search path to the end of the
+    * search path.  The system search path
+    * usually includes the platform library, extension
+    * libraries, and the search path specified by the
+    * <code>-classpath</code> option or the <code>CLASSPATH</code>
+    * environment variable.
+    *
+    * @return the appended class path.
+    */
+   public ClassPath appendSystemPath()
+   {
+      return source.appendSystemPath();
+   }
+
+   /**
+    * Insert a <code>ClassPath</code> object at the head of the
+    * search path.
+    *
+    * @return the inserted class path.
+    * @see javassist.ClassPath
+    * @see javassist.URLClassPath
+    * @see javassist.ByteArrayClassPath
+    */
+   public ClassPath insertClassPath(ClassPath cp)
+   {
+      return source.insertClassPath(cp);
+   }
+
+   /**
+    * Appends a <code>ClassPath</code> object to the end of the
+    * search path.
+    *
+    * @return the appended class path.
+    * @see javassist.ClassPath
+    * @see javassist.URLClassPath
+    * @see javassist.ByteArrayClassPath
+    */
+   public ClassPath appendClassPath(ClassPath cp)
+   {
+      return source.appendClassPath(cp);
+   }
+
+   /**
+    * Inserts a directory or a jar (or zip) file at the head of the
+    * search path.
+    *
+    * @param pathname the path name of the directory or jar file.
+    *                 It must not end with a path separator ("/").
+    * @return the inserted class path.
+    * @throws NotFoundException if the jar file is not found.
+    */
+   public ClassPath insertClassPath(String pathname)
+           throws NotFoundException
+   {
+      return source.insertClassPath(pathname);
+   }
+
+   /**
+    * Appends a directory or a jar (or zip) file to the end of the
+    * search path.
+    *
+    * @param pathname the path name of the directory or jar file.
+    *                 It must not end with a path separator ("/").
+    * @return the appended class path.
+    * @throws NotFoundException if the jar file is not found.
+    */
+   public ClassPath appendClassPath(String pathname)
+           throws NotFoundException
+   {
+      return source.appendClassPath(pathname);
+   }
+
+   /**
+    * Detatches the <code>ClassPath</code> object from the search path.
+    * The detached <code>ClassPath</code> object cannot be added
+    * to the pathagain.
+    */
+   public void removeClassPath(ClassPath cp)
+   {
+      source.removeClassPath(cp);
+   }
+
+   /**
+    * Appends directories and jar files for search.
+    * <p/>
+    * <p>The elements of the given path list must be separated by colons
+    * in Unix or semi-colons in Windows.
+    *
+    * @param pathlist a (semi)colon-separated list of
+    *                 the path names of directories and jar files.
+    *                 The directory name must not end with a path
+    *                 separator ("/").
+    * @throws NotFoundException if a jar file is not found.
+    */
+   public void appendPathList(String pathlist) throws NotFoundException
+   {
+      char sep = File.pathSeparatorChar;
+      int i = 0;
+      for (; ;)
+      {
+         int j = pathlist.indexOf(sep, i);
+         if (j < 0)
+         {
+            appendClassPath(pathlist.substring(i));
+            break;
+         }
+         else
+         {
+            appendClassPath(pathlist.substring(i, j));
+            i = j + 1;
+         }
+      }
+   }
+
+   /**
+    * Converts this class to a <code>java.lang.Class</code> object.
+    * Once this method is called, further modifications are not
+    * allowed any more.
+    * To load the class, this method uses the context class loader
+    * of the current thread.  If the program is running on some application
+    * server, the context class loader might be inappropriate to load the
+    * class.
+    * <p/>
+    * <p>This method is provided for convenience.  If you need more
+    * complex functionality, you should write your own class loader.
+    *
+    * @see #toClass(java.lang.ClassLoader)
+    */
+   public Class toClass(CtClass clazz)
+           throws CannotCompileException
+   {
+      return toClass(clazz, Thread.currentThread().getContextClassLoader());
+   }
+
+   /**
+    * Converts this class to a <code>java.lang.Class</code> object.
+    * Once this method is called, further modifications are not allowed
+    * any more.
+    * <p/>
+    * <p>The class file represented by this <code>CtClass</code> is
+    * loaded by the given class loader to construct a
+    * <code>java.lang.Class</code> object.  Since a private method
+    * on the class loader is invoked through the reflection API,
+    * the caller must have permissions to do that.
+    * <p/>
+    * <p>This method is provided for convenience.  If you need more
+    * complex functionality, you should write your own class loader.
+    *
+    * @param loader the class loader used to load this class.
+    */
+   public Class toClass(CtClass ct, ClassLoader loader)
+           throws CannotCompileException
+   {
+      try
+      {
+         byte[] b = ct.toBytecode();
+         Class cl = Class.forName("java.lang.ClassLoader");
+         java.lang.reflect.Method method
+                 = cl.getDeclaredMethod("defineClass",
+                         new Class[]{String.class, byte[].class,
+                                     int.class, int.class});
+         method.setAccessible(true);
+         Object[] args = new Object[]{ct.getName(), b, new Integer(0),
+                                      new Integer(b.length)};
+         Class clazz = (Class) method.invoke(loader, args);
+         method.setAccessible(false);
+         return clazz;
+      }
+      catch (RuntimeException e)
+      {
+         throw e;
+      }
+      catch (java.lang.reflect.InvocationTargetException e)
+      {
+         throw new CannotCompileException(e.getTargetException());
+      }
+      catch (Exception e)
+      {
+         throw new CannotCompileException(e);
+      }
+   }
+
 }
 
index 0e435d786dbf64eadf1c97d905a54a7bcd7b739b..5a1805ccdddf23ed1f4f366362a1f5efb65aec18 100644 (file)
 
 package javassist;
 
-import java.io.*;
-import javassist.bytecode.*;
-import java.util.Collection;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.Opcode;
 import javassist.expr.ExprEditor;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.net.URL;
+import java.util.Collection;
 
 // Subclasses of CtClass: CtClassType, CtPrimitiveType, and CtArray
 
@@ -29,1069 +38,1141 @@ import java.net.URL;
  *
  * @see ClassPool#get(String)
  */
-public abstract class CtClass {
-    protected String qualifiedName;
-
-    /**
-     * The version number of this release.
-     */
-    public static final String version = "3.0 RC1";
-
-    /**
-     * Prints the version number and the copyright notice.
-     *
-     * <p>The following command invokes this method:
-     *
-     * <ul><pre>java -jar javassist.jar</pre></ul>
-     */
-    public static void main(String[] args) {
-        System.out.println("Javassist version " + CtClass.version);
-        System.out.println("Copyright (C) 1999-2004 Shigeru Chiba."
-                           + " All Rights Reserved.");
-    }
-
-    static final String javaLangObject = "java.lang.Object";
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>boolean</code> type.
-     */
-    public static CtClass booleanType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>char</code> type.
-     */
-    public static CtClass charType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>byte</code> type.
-     */
-    public static CtClass byteType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>short</code> type.
-     */
-    public static CtClass shortType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>int</code> type.
-     */
-    public static CtClass intType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>long</code> type.
-     */
-    public static CtClass longType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>float</code> type.
-     */
-    public static CtClass floatType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>double</code> type.
-     */
-    public static CtClass doubleType;
-
-    /**
-     * The <code>CtClass</code> object representing
-     * the <code>void</code> type.
-     */
-    public static CtClass voidType;
-
-    static CtClass[] primitiveTypes;
-
-    static {
-        primitiveTypes = new CtClass[9];
-
-        booleanType = new CtPrimitiveType("boolean", 'Z', "java.lang.Boolean",
-                                "booleanValue", "()Z", Opcode.IRETURN,
-                                Opcode.T_BOOLEAN, 1);
-        primitiveTypes[0] = booleanType;
-
-        charType = new CtPrimitiveType("char", 'C', "java.lang.Character",
-                                "charValue", "()C", Opcode.IRETURN,
-                                Opcode.T_CHAR, 1);
-        primitiveTypes[1] = charType;
-
-        byteType = new CtPrimitiveType("byte", 'B', "java.lang.Byte",
-                                "byteValue", "()B", Opcode.IRETURN,
-                                Opcode.T_BYTE, 1);
-        primitiveTypes[2] = byteType;
-
-        shortType = new CtPrimitiveType("short", 'S', "java.lang.Short",
-                                "shortValue", "()S", Opcode.IRETURN,
-                                Opcode.T_SHORT, 1);
-        primitiveTypes[3] = shortType;
-
-        intType = new CtPrimitiveType("int", 'I', "java.lang.Integer",
-                                "intValue", "()I", Opcode.IRETURN,
-                                Opcode.T_INT, 1);
-        primitiveTypes[4] = intType;
-
-        longType = new CtPrimitiveType("long", 'J', "java.lang.Long",
-                                "longValue", "()J", Opcode.LRETURN,
-                                Opcode.T_LONG, 2);
-        primitiveTypes[5] = longType;
-
-        floatType = new CtPrimitiveType("float", 'F', "java.lang.Float",
-                                "floatValue", "()F", Opcode.FRETURN,
-                                Opcode.T_FLOAT, 1);
-        primitiveTypes[6] = floatType;
-
-        doubleType = new CtPrimitiveType("double", 'D', "java.lang.Double",
-                                "doubleValue", "()D", Opcode.DRETURN,
-                                Opcode.T_DOUBLE, 2);
-        primitiveTypes[7] = doubleType;
-
-        voidType = new CtPrimitiveType("void", 'V', "java.lang.Void",
-                                null, null, Opcode.RETURN, 0, 0);
-        primitiveTypes[8] = voidType;
-    }
-
-    protected CtClass(String name) {
-        qualifiedName = name;
-    }
-
-    /**
-     * Converts the object to a string.
-     */
-    public String toString() {
-        StringBuffer buf = new StringBuffer(getClass().getName());
-        buf.append("@");
-        buf.append(Integer.toHexString(hashCode()));
-        buf.append("[");
-        extendToString(buf);
-        buf.append("]");
-        return buf.toString();
-    }    
-
-    /**
-     * Implemented in subclasses to add to the {@link #toString()} result.
-     * Subclasses should put a space before each token added to the buffer.
-     */
-    protected void extendToString(StringBuffer buffer) {
-        buffer.append(getName());
-    }
-
-    /**
-     * Returns a <code>ClassPool</code> for this class.
-     */
-    public ClassPool getClassPool() { return null; }
-
-    /**
-     * Returns a class file for this class.
-     *
-     * <p>This method is not available if <code>isFrozen()</code>
-     * is true.
-     */
-    public ClassFile getClassFile() {
-        checkModify();
-        return getClassFile2();
-    }
-
-    /**
-     * Undocumented method.  Do not use; internal-use only.
-     */
-    public ClassFile getClassFile2() { return null; }
-
-    /**
-     * Undocumented method.  Do not use; internal-use only.
-     */
-    public javassist.compiler.AccessorMaker getAccessorMaker() {
-        return null;
-    }
-
-    /**
-     * Returns the uniform resource locator (URL) of the class file.
-     */
-    public URL getURL() throws NotFoundException {
-        throw new NotFoundException(getName());
-    }
-
-    /**
-     * Returns true if the definition of the class has been modified.
-     */
-    public boolean isModified() { return false; }
-
-    /**
-     * Returns true if the class has been loaded or written out
-     * and thus it cannot be modified any more.
-     *
-     * @see #defrost()
-     */
-    public boolean isFrozen() { return true; }
-
-    void freeze() {}
-
-    void checkModify() throws RuntimeException {
-        if (isFrozen())
-            throw new RuntimeException(getName() + " class is frozen");
-
-        // isModified() must return true after this method is invoked.
-    }
-
-    /**
-     * Defrosts the class so that the class can be modified again.
-     *
-     * <p>To avoid changes that will be never reflected,
-     * the class is frozen to be unmodifiable if it is loaded or
-     * written out.  This method should be called only in a case
-     * that the class will be reloaded or written out later again.
-     *
-     * <p>If <code>defrost()</code> will be called later, pruning
-     * must be disallowed in advance.
-     *
-     * @see #isFrozen()
-     * @see #stopPruning(boolean)
-     */
-    public void defrost() {
-        throw new RuntimeException("cannot defrost " + getName());
-    }
-
-    /**
-     * Disallows (or allows) pruning the data structure on memory
-     * when this <code>CtClass</code> object is converted into a class file.
-     * Pruning saves memory space since a <code>ClassPool</code> holds
-     * all instances of <code>CtClass</code>
-     * all the time of program execution.
-     * However, pruning discards the data representing part of the
-     * class definition, such as method bodies.
-     * Therefore, once it is pruned, <code>toBytecode()</code>,
-     * <code>writeFile()</code>, or <code>toClass()</code> cannot
-     * be called again.
-     *
-     * <p>Initially, pruning is allowed.
-     *
-     * @param stop      disallow pruning if true.  Otherwise, allow.
-     * @see #detach()
-     * @see #toBytecode()
-     * @see #toClass()
-     * @see #writeFile()
-     */
-    public void stopPruning(boolean stop) {}
-
-    /* Called by get() in ClassPool.
-     * CtClassType overrides this method.
-     */
-    void incGetCounter() {}
-
-    /**
-     * Returns <code>true</code> if this object represents a primitive
-     * Java type: boolean, byte, char, short, int, long, float, double,
-     * or void.
-     */
-    public boolean isPrimitive() { return false; }
-
-    /**
-     * Returns <code>true</code> if this object represents an array type.
-     */
-    public boolean isArray() {
-        return false;
-    }
-
-    /**
-     * If this object represents an array, this method returns the component
-     * type of the array.  Otherwise, it returns <code>null</code>.
-     */
-    public CtClass getComponentType() throws NotFoundException {
-        return null;
-    }
-
-    /**
-     * Returns <code>true</code> if this class extends or implements
-     * <code>clazz</code>.  It also returns <code>true</code> if
-     * this class is the same as <code>clazz</code>.
-     */
-    public boolean subtypeOf(CtClass clazz) throws NotFoundException {
-        return this == clazz || getName().equals(clazz.getName());
-    }
-
-    /**
-     * Obtains the fully-qualified name of the class.
-     */
-    public String getName() { return qualifiedName; }
-
-    /**
-     * Obtains the not-qualified class name.
-     */
-    public final String getSimpleName() {
-        String qname = qualifiedName;
-        int index = qname.lastIndexOf('.');
-        if (index < 0)
-            return qname;
-        else
-            return qname.substring(index + 1);
-    }
-
-    /**
-     * Obtains the package name.  It may be <code>null</code>.
-     */
-    public final String getPackageName() {
-        String qname = qualifiedName;
-        int index = qname.lastIndexOf('.');
-        if (index < 0)
-            return null;
-        else
-            return qname.substring(0, index);
-    }
-
-    /**
-     * Sets the class name
-     *
-     * @param name      fully-qualified name
-     */
-    public void setName(String name) {
-        checkModify();
-        if (name != null)
-            qualifiedName = name;
-    }
-
-    /**
-     * Substitutes <code>newName</code> for all occurrences of a class
-     * name <code>oldName</code> in the class file.
-     *
-     * @param oldName           replaced class name
-     * @param newName           substituted class name
-     */
-    public void replaceClassName(String oldName, String newName) {
-        checkModify();
-    }
-
-    /**
-     * Changes class names appearing in the class file according to the
-     * given <code>map</code>.
-     *
-     * <p>All the class names appearing in the class file are tested
-     * with <code>map</code> to determine whether each class name is
-     * replaced or not.  Thus this method can be used for collecting
-     * all the class names in the class file.  To do that, first define
-     * a subclass of <code>ClassMap</code> so that <code>get()</code>
-     * records all the given parameters.  Then, make an instance of
-     * that subclass as an empty hash-table.  Finally, pass that instance
-     * to this method.  After this method finishes, that instance would
-     * contain all the class names appearing in the class file.
-     *
-     * @param map       the hashtable associating replaced class names
-     *                  with substituted names.
-     */
-    public void replaceClassName(ClassMap map) {
-        checkModify();
-    }
-
-    /**
-     * Returns a collection of the names of all the classes
-     * referenced in this class.
-     * That collection includes the name of this class.
-     *
-     * <p>This method may return <code>null</code>.
-     */
-    public Collection getRefClasses() {
-        ClassFile cf = getClassFile2();
-        if (cf != null) {
-            ClassMap cm = new ClassMap() {
-                    public void put(String oldname, String newname) {
-                        put0(oldname, newname);
-                    }
-
-                    public Object get(Object jvmClassName) {
-                        String n = toJavaName((String)jvmClassName);
-                        put0(n, n);
-                        return null;
-                    }
-
-                    public void fix(String name) {}
-                };
-            cf.renameClass(cm);
-            return cm.values();
-        }
-        else
-            return null;
-    }
-
-    /**
-     * Determines whether this object represents a class or an interface.
-     * It returns <code>true</code> if this object represents an interface.
-     */
-    public boolean isInterface() {
-        return false;
-    }
-
-    /**
-     * Returns the modifiers for this class, encoded in an integer.
-     * For decoding, use <code>javassist.Modifier</code>.
-     *
-     * @see Modifier
-     */
-    public int getModifiers() {
-        return 0;
-    }
-
-    /**
-     * Sets the modifiers.
-     *
-     * @param mod       modifiers encoded by
-     *                  <code>javassist.Modifier</code>
-     * @see Modifier
-     */
-    public void setModifiers(int mod) {
-        checkModify();
-    }
-
-    /**
-     * Determines whether the class directly or indirectly extends
-     * the given class.  If this class extends a class A and
-     * the class A extends a class B, then subclassof(B) returns true.
-     *
-     * <p>This method returns true if the given class is identical to
-     * the class represented by this object.
-     */
-    public boolean subclassOf(CtClass superclass) {
-        return false;
-    }
-
-    /**
-     * Obtains the class object representing the superclass of the
-     * class.
-     * It returns null if this object represents the
-     * <code>java.lang.Object</code> class and thus it does not have
-     * the super class.
-     *
-     * <p>If this object represents an interface, this method
-     * always returns the <code>java.lang.Object</code> class.
-     * To obtain the super interfaces
-     * extended by that interface, call <code>getInterfaces()</code>.
-     */
-    public CtClass getSuperclass() throws NotFoundException {
-        return null;
-    }
-
-    /**
-     * Changes a super class unless this object represents an interface.
-     * The new super class must be compatible with the old one.
-     *
-     * <p>If this object represents an interface, this method is equivalent
-     * to <code>addInterface()</code>; it appends <code>clazz</code> to
-     * the list of the super interfaces extended by that interface.
-     * Note that an interface can extend multiple super interfaces.
-     */
-    public void setSuperclass(CtClass clazz) throws CannotCompileException {
-        checkModify();
-    }
-
-    /**
-     * Obtains the class objects representing the interfaces implemented
-     * by the class or, if this object represents an interface, the interfaces
-     * extended by that interface.
-     */
-    public CtClass[] getInterfaces() throws NotFoundException {
-        return new CtClass[0];
-    }
-
-    /**
-     * Sets implemented interfaces.  If this object represents an interface,
-     * this method sets the interfaces extended by that interface.
-     *
-     * @param list              a list of the <code>CtClass</code> objects
-     *                          representing interfaces, or
-     *                          <code>null</code> if the class implements
-     *                          no interfaces.
-     */
-    public void setInterfaces(CtClass[] list) {
-        checkModify();
-    }
-
-    /**
-     * Adds an interface.
-     *
-     * @param anInterface       the added interface.
-     */
-    public void addInterface(CtClass anInterface) {
-        checkModify();
-    }
-
-    /**
-     * If this class is a member class or interface of another class,
-     * then the class enclosing this class is returned.
-     *
-     * @return null if this class is a top-level class.
-     */
-    public CtClass getDeclaringClass() throws NotFoundException {
-        return null;
-    }
-
-    /**
-     * Makes a new nested class.  Making a nested class modifies the
-     * data in this <code>CtClass</code>.
-     *
-     * <p>The current implementation only supports a static nested class.
-     * <code>isStatic</code> must be true.
-     *
-     * @param name          the simple name of the nested class.
-     * @param isStatic      true if the nested class is static.
-     */
-    public CtClass makeNestedClass(String name, boolean isStatic) {
-        throw new RuntimeException(getName() + " is not a class");
-    }
-
-    /**
-     * Returns an array containing <code>CtField</code> objects
-     * representing all the public fields of the class.
-     * That array includes public fields inherited from the
-     * superclasses.
-     */
-    public CtField[] getFields() { return new CtField[0]; }
-
-    /**
-     * Returns the field with the specified name.  The returned field
-     * may be a private field declared in a super class or interface.
-     */
-    public CtField getField(String name) throws NotFoundException {
-        throw new NotFoundException(name);
-    }
-
-    /**
-     * @return null     if the specified field is not found.
-     */
-    CtField getField2(String name) { return null; }
-
-    /**
-     * Gets all the fields declared in the class.  The inherited fields
-     * are not included.
-     *
-     * <p>Note: the result does not include inherited fields.
-     */
-    public CtField[] getDeclaredFields() { return new CtField[0]; }
-
-    /**
-     * Retrieves the field with the specified name among the fields
-     * declared in the class.
-     *
-     * <p>Note: this method does not search the superclasses.
-     */
-    public CtField getDeclaredField(String name) throws NotFoundException {
-        throw new NotFoundException(name);
-    }
-
-    /**
-     * Gets all the constructors and methods declared in the class.
-     */
-    public CtBehavior[] getDeclaredBehaviors() {
-        return new CtBehavior[0];
-    }
-
-    /**
-     * Returns an array containing <code>CtConstructor</code> objects
-     * representing all the public constructors of the class.
-     */
-    public CtConstructor[] getConstructors() {
-        return new CtConstructor[0];
-    }
-
-    /**
-     * Returns the constructor with the given signature,
-     * which is represented by a character string
-     * called method descriptor.
-     * For details of the method descriptor, see the JVM specification
-     * or <code>javassist.bytecode.Descriptor</code>.
-     *
-     * @param desc      method descriptor
-     * @see javassist.bytecode.Descriptor
-     */
-    public CtConstructor getConstructor(String desc)
-        throws NotFoundException
-    {
-        throw new NotFoundException("no such a constructor");
-    }
-
-    /**
-     * Gets all the constructors declared in the class.
-     *
-     * @see javassist.CtConstructor
-     */
-    public CtConstructor[] getDeclaredConstructors() {
-        return new CtConstructor[0];
-    }
-
-    /**
-     * Returns a constructor receiving the specified parameters.
-     *
-     * @param params    parameter types.
-     */
-    public CtConstructor getDeclaredConstructor(CtClass[] params)
-        throws NotFoundException
-    {
-        String desc = Descriptor.ofConstructor(params);
-        return getConstructor(desc);
-    }
-
-    /**
-     * Gets the class initializer (static constructor)
-     * declared in the class.
-     * This method returns <code>null</code> if
-     * no class initializer is not declared.
-     *
-     * @see #makeClassInitializer()
-     * @see javassist.CtConstructor
-     */
-    public CtConstructor getClassInitializer() {
-        return null;
-    }
-
-    /**
-     * Returns an array containing <code>CtMethod</code> objects
-     * representing all the public methods of the class.
-     * That array includes public methods inherited from the
-     * superclasses.
-     */
-    public CtMethod[] getMethods() {
-        return new CtMethod[0];
-    }
-
-    /**
-     * Returns the method with the given name and signature.
-     * The returned method may be declared in a super class.
-     * The method signature is represented by a character string
-     * called method descriptor,
-     * which is defined in the JVM specification.
-     *
-     * @param name      method name
-     * @param desc      method descriptor
-     * @see javassist.bytecode.Descriptor
-     */
-    public CtMethod getMethod(String name, String desc)
-        throws NotFoundException
-    {
-        throw new NotFoundException(name);
-    }
-
-    /**
-     * Gets all methods declared in the class.  The inherited methods
-     * are not included.
-     *
-     * @see javassist.CtMethod
-     */
-    public CtMethod[] getDeclaredMethods() {
-        return new CtMethod[0];
-    }
-
-    /**
-     * Retrieves the method with the specified name and parameter types
-     * among the methods declared in the class.
-     *
-     * <p>Note: this method does not search the superclasses.
-     *
-     * @param name              method name
-     * @param params            parameter types
-     * @see javassist.CtMethod
-     */
-    public CtMethod getDeclaredMethod(String name, CtClass[] params)
-        throws NotFoundException
-    {
-        throw new NotFoundException(name);
-    }
-
-    /**
-     * Retrieves the method with the specified name among the methods
-     * declared in the class.  If there are multiple methods with
-     * the specified name, then this method returns one of them.
-     *
-     * <p>Note: this method does not search the superclasses.
-     *
-     * @see javassist.CtMethod
-     */
-    public CtMethod getDeclaredMethod(String name) throws NotFoundException {
-        throw new NotFoundException(name);
-    }
-
-    /**
-     * Makes an empty class initializer (static constructor).
-     * If the class already includes a class initializer,
-     * this method returns it.
-     *
-     * @see #getClassInitializer()
-     */
-    public CtConstructor makeClassInitializer()
-        throws CannotCompileException
-    {
-        throw new CannotCompileException("not a class");
-    }
-
-    /**
-     * Adds a constructor.  To add a class initializer (static constructor),
-     * call <code>makeClassInitializer()</code>.
-     *
-     * @see #makeClassInitializer()
-     */
-    public void addConstructor(CtConstructor c)
-        throws CannotCompileException
-    {
-        checkModify();
-    }
-
-    /**
-     * Adds a method.
-     */
-    public void addMethod(CtMethod m) throws CannotCompileException {
-        checkModify();
-    }
-
-    /**
-     * Adds a field.
-     *
-     * <p>The <code>CtField</code> belonging to another
-     * <code>CtClass</code> cannot be directly added to this class.
-     * Only a field created for this class can be added.
-     *
-     * @see javassist.CtField#CtField(CtField,CtClass)
-     */
-    public void addField(CtField f) throws CannotCompileException {
-        addField(f, (CtField.Initializer)null);
-    }
-
-    /**
-     * Adds a field with an initial value.
-     *
-     * <p>The <code>CtField</code> belonging to another
-     * <code>CtClass</code> cannot be directly added to this class.
-     * Only a field created for this class can be added.
-     *
-     * <p>The initial value is given as an expression written in Java.
-     * Any regular Java expression can be used for specifying the initial
-     * value.  The followings are examples.
-     *
-     * <ul><pre>
-     * cc.addField(f, "0")               // the initial value is 0.
-     * cc.addField(f, "i + 1")           // i + 1.
-     * cc.addField(f, "new Point()");    // a Point object.
-     * </pre></ul>
-     *
-     * <p>Here, the type of variable <code>cc</code> is <code>CtClass</code>.
-     * The type of <code>f</code> is <code>CtField</code>.
-     *
-     * @param init      an expression for the initial value.
-     *
-     * @see javassist.CtField.Initializer#byExpr(String)
-     * @see javassist.CtField#CtField(CtField,CtClass)
-     */
-    public void addField(CtField f, String init)
-        throws CannotCompileException
-    {
-        checkModify();
-    }
-
-    /**
-     * Adds a field with an initial value.
-     *
-     * <p>The <code>CtField</code> belonging to another
-     * <code>CtClass</code> cannot be directly added to this class.
-     * Only a field created for this class can be added.
-     *
-     * <p>For example,
-     *
-     * <ul><pre>
-     * CtClass cc = ...;
-     * addField(new CtField(CtClass.intType, "i", cc),
-     *          CtField.Initializer.constant(1));
-     * </pre></ul>
-     *
-     * <p>This code adds an <code>int</code> field named "i".  The
-     * initial value of this field is 1.
-     *
-     * @param init      specifies the initial value of the field.
-     *
-     * @see javassist.CtField#CtField(CtField,CtClass)
-     */
-    public void addField(CtField f, CtField.Initializer init)
-        throws CannotCompileException
-    {
-        checkModify();
-    }
-
-    /**
-     * Obtains an attribute with the given name.
-     * If that attribute is not found in the class file, this
-     * method returns null.
-     *
-     * <p>This is a convenient method mainly for obtaining
-     * a user-defined attribute.  For dealing with attributes, see the
-     * <code>javassist.bytecode</code> package.  For example, the following
-     * expression returns all the attributes of a class file.
-     *
-     * <ul><pre>
-     * getClassFile().getAttributes()
-     * </pre></ul>
-     *
-     * @param name              attribute name
-     * @see javassist.bytecode.AttributeInfo
-     */
-    public byte[] getAttribute(String name) {
-        return null;
-    }
-
-    /**
-     * Adds a named attribute.
-     * An arbitrary data (smaller than 64Kb) can be saved in the class
-     * file.  Some attribute name are reserved by the JVM.
-     * The attributes with the non-reserved names are ignored when a
-     * class file is loaded into the JVM.
-     * If there is already an attribute with
-     * the same name, this method substitutes the new one for it.
-     *
-     * <p>This is a convenient method mainly for adding
-     * a user-defined attribute.  For dealing with attributes, see the
-     * <code>javassist.bytecode</code> package.  For example, the following
-     * expression adds an attribute of a class file.
-     *
-     * <ul><pre>
-     * getClassFile().addAttribute(info)
-     * </pre></ul>
-     *
-     * @param name      attribute name
-     * @param data      attribute value
-     * @see javassist.bytecode.AttributeInfo
-     */
-    public void setAttribute(String name, byte[] data) {
-        checkModify();
-    }
-
-    /**
-     * Applies the given converter to all methods and constructors
-     * declared in the class.  This method calls <code>instrument()</code>
-     * on every <code>CtMethod</code> and <code>CtConstructor</code> object
-     * in the class.
-     *
-     * @param converter         specifies how to modify.
-     */
-    public void instrument(CodeConverter converter)
-        throws CannotCompileException
-    {
-        checkModify();
-    }
-
-    /**
-     * Modifies the bodies of all methods and constructors
-     * declared in the class.  This method calls <code>instrument()</code>
-     * on every <code>CtMethod</code> and <code>CtConstructor</code> object
-     * in the class.
-     *
-     * @param editor            specifies how to modify.
-     */
-    public void instrument(ExprEditor editor)
-        throws CannotCompileException
-    {
-        checkModify();
-    }
-
-    /**
-     * Converts this class to a <code>java.lang.Class</code> object.
-     * Once this method is called, further modifications are not
-     * allowed any more.
-     * To load the class, this method uses the context class loader
-     * of the current thread.  If the program is running on some application
-     * server, the context class loader might be inappropriate to load the
-     * class.
-     *
-     * <p>This method is provided for convenience.  If you need more
-     * complex functionality, you should write your own class loader.
-     *
-     * @see #toClass(java.lang.ClassLoader)
-     */
-    public Class toClass()
-        throws CannotCompileException
-    {
-        return toClass(Thread.currentThread().getContextClassLoader());
-    }
-
-    /**
-     * Converts this class to a <code>java.lang.Class</code> object.
-     * Once this method is called, further modifications are not allowed
-     * any more.
-     *
-     * <p>The class file represented by this <code>CtClass</code> is
-     * loaded by the given class loader to construct a
-     * <code>java.lang.Class</code> object.  Since a private method
-     * on the class loader is invoked through the reflection API,
-     * the caller must have permissions to do that. 
-     *
-     * <p>This method is provided for convenience.  If you need more
-     * complex functionality, you should write your own class loader.
-     *
-     * @param loader        the class loader used to load this class.
-     */
-    public Class toClass(ClassLoader loader)
-        throws CannotCompileException
-    {
-        try {
-            byte[] b = toBytecode();
-            Class cl = Class.forName("java.lang.ClassLoader");
-            java.lang.reflect.Method method
-                = cl.getDeclaredMethod("defineClass",
-                                new Class[] { String.class, byte[].class,
-                                              int.class, int.class });
-            method.setAccessible(true);
-            Object[] args = new Object[] { getName(), b, new Integer(0),
-                                           new Integer(b.length)};
-            Class clazz = (Class)method.invoke(loader, args);
-            method.setAccessible(false);
-            return clazz;
-        }
-        catch (RuntimeException e) {
-            throw e;
-        }
-        catch (java.lang.reflect.InvocationTargetException e) {
-            throw new CannotCompileException(e.getTargetException());
-        }
-        catch (Exception e) {
-            throw new CannotCompileException(e);
-        }
-    }
-
-    /**
-     * Removes this <code>CtClass</code> object from the
-     * <code>ClassPool</code>.
-     * After this method is called, any method cannot be called on the
-     * removed <code>CtClass</code> object.
-     *
-     * <p>If <code>get()</code> in <code>ClassPool</code> is called
-     * with the name of the removed method,
-     * the <code>ClassPool</code> will read the class file again
-     * and constructs another <code>CtClass</code> object representing
-     * the same class.
-     */
-    public void detach() {
-        ClassPool cp = getClassPool();
-        CtClass obj = cp.removeCached(getName());
-        if (obj != this)
-            cp.cacheCtClass(getName(), obj);
-    }
-
-    /**
-     * Converts this class to a class file.
-     * Once this method is called, further modifications are not
-     * possible any more.
-     *
-     * @return the contents of the class file.
-     */
-    public byte[] toBytecode()
-        throws IOException, CannotCompileException
-    {
-        ByteArrayOutputStream barray = new ByteArrayOutputStream();
-        DataOutputStream out = new DataOutputStream(barray);
-        try {
-            toBytecode(out);
-        }
-        finally {
-            out.close();
-        }
-
-        return barray.toByteArray();
-    }
-
-    /**
-     * Writes a class file represented by this <code>CtClass</code>
-     * object in the current directory.
-     * Once this method is called, further modifications are not
-     * possible any more.
-     */
-    public void writeFile()
-        throws NotFoundException, IOException, CannotCompileException
-    {
-        writeFile(".");
-    }
-
-    /**
-     * Writes a class file represented by this <code>CtClass</code>
-     * object on a local disk.
-     * Once this method is called, further modifications are not
-     * possible any more.
-     *
-     * @param directoryName     it must end without a directory separator.
-     */
-    public void writeFile(String directoryName)
-        throws NotFoundException, CannotCompileException, IOException
-    {
-        String classname = getName();
-        String filename = directoryName + File.separatorChar
-            + classname.replace('.', File.separatorChar) + ".class";
-        int pos = filename.lastIndexOf(File.separatorChar);
-        if (pos > 0) {
-            String dir = filename.substring(0, pos);
-            if (!dir.equals("."))
-                new File(dir).mkdirs();
-        }
-
-        DataOutputStream out
-            = new DataOutputStream(new BufferedOutputStream(
-                                new DelayedFileOutputStream(filename)));
-        try {
-            toBytecode(out);
-        }
-        finally {
-            out.close();
-        }
-    }
-
-    static class DelayedFileOutputStream extends OutputStream {
-        private FileOutputStream file;
-        private String filename;
-
-        DelayedFileOutputStream(String name) {
-            file = null;
-            filename = name;
-        }
-
-        private void init() throws IOException {
-            if (file == null)
-                file = new FileOutputStream(filename);
-        }
-
-        public void write(int b) throws IOException {
-            init();
-            file.write(b);
-        }
-
-        public void write(byte[] b) throws IOException {
-            init();
-            file.write(b);
-        }
-
-        public void write(byte[] b, int off, int len) throws IOException {
-            init();
-            file.write(b, off, len);
-
-        }
-
-        public void flush() throws IOException {
-            init();
-            file.flush();
-        }
-
-        public void close() throws IOException {
-            init();
-            file.close();
-        }
-    }
-
-    /**
-     * Converts this class to a class file.
-     * Once this method is called, further modifications are not
-     * possible any more.
-     *
-     * <p>This method dose not close the output stream in the end.
-     *
-     * @param out       the output stream that a class file is written to.
-     */
-    public void toBytecode(DataOutputStream out)
-        throws CannotCompileException, IOException
-    {
-        throw new CannotCompileException("not a class");
-    }
+public abstract class CtClass
+{
+   protected String qualifiedName;
+
+   /**
+    * The version number of this release.
+    */
+   public static final String version = "3.0 RC1";
+
+   /**
+    * Prints the version number and the copyright notice.
+    * <p/>
+    * <p>The following command invokes this method:
+    * <p/>
+    * <ul><pre>java -jar javassist.jar</pre></ul>
+    */
+   public static void main(String[] args)
+   {
+      System.out.println("Javassist version " + CtClass.version);
+      System.out.println("Copyright (C) 1999-2004 Shigeru Chiba."
+              + " All Rights Reserved.");
+   }
+
+   static final String javaLangObject = "java.lang.Object";
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>boolean</code> type.
+    */
+   public static CtClass booleanType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>char</code> type.
+    */
+   public static CtClass charType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>byte</code> type.
+    */
+   public static CtClass byteType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>short</code> type.
+    */
+   public static CtClass shortType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>int</code> type.
+    */
+   public static CtClass intType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>long</code> type.
+    */
+   public static CtClass longType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>float</code> type.
+    */
+   public static CtClass floatType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>double</code> type.
+    */
+   public static CtClass doubleType;
+
+   /**
+    * The <code>CtClass</code> object representing
+    * the <code>void</code> type.
+    */
+   public static CtClass voidType;
+
+   static CtClass[] primitiveTypes;
+
+   static
+   {
+      primitiveTypes = new CtClass[9];
+
+      booleanType = new CtPrimitiveType("boolean", 'Z', "java.lang.Boolean",
+              "booleanValue", "()Z", Opcode.IRETURN,
+              Opcode.T_BOOLEAN, 1);
+      primitiveTypes[0] = booleanType;
+
+      charType = new CtPrimitiveType("char", 'C', "java.lang.Character",
+              "charValue", "()C", Opcode.IRETURN,
+              Opcode.T_CHAR, 1);
+      primitiveTypes[1] = charType;
+
+      byteType = new CtPrimitiveType("byte", 'B', "java.lang.Byte",
+              "byteValue", "()B", Opcode.IRETURN,
+              Opcode.T_BYTE, 1);
+      primitiveTypes[2] = byteType;
+
+      shortType = new CtPrimitiveType("short", 'S', "java.lang.Short",
+              "shortValue", "()S", Opcode.IRETURN,
+              Opcode.T_SHORT, 1);
+      primitiveTypes[3] = shortType;
+
+      intType = new CtPrimitiveType("int", 'I', "java.lang.Integer",
+              "intValue", "()I", Opcode.IRETURN,
+              Opcode.T_INT, 1);
+      primitiveTypes[4] = intType;
+
+      longType = new CtPrimitiveType("long", 'J', "java.lang.Long",
+              "longValue", "()J", Opcode.LRETURN,
+              Opcode.T_LONG, 2);
+      primitiveTypes[5] = longType;
+
+      floatType = new CtPrimitiveType("float", 'F', "java.lang.Float",
+              "floatValue", "()F", Opcode.FRETURN,
+              Opcode.T_FLOAT, 1);
+      primitiveTypes[6] = floatType;
+
+      doubleType = new CtPrimitiveType("double", 'D', "java.lang.Double",
+              "doubleValue", "()D", Opcode.DRETURN,
+              Opcode.T_DOUBLE, 2);
+      primitiveTypes[7] = doubleType;
+
+      voidType = new CtPrimitiveType("void", 'V', "java.lang.Void",
+              null, null, Opcode.RETURN, 0, 0);
+      primitiveTypes[8] = voidType;
+   }
+
+   protected CtClass(String name)
+   {
+      qualifiedName = name;
+   }
+
+   /**
+    * Converts the object to a string.
+    */
+   public String toString()
+   {
+      StringBuffer buf = new StringBuffer(getClass().getName());
+      buf.append("@");
+      buf.append(Integer.toHexString(hashCode()));
+      buf.append("[");
+      extendToString(buf);
+      buf.append("]");
+      return buf.toString();
+   }
+
+   /**
+    * Implemented in subclasses to add to the {@link #toString()} result.
+    * Subclasses should put a space before each token added to the buffer.
+    */
+   protected void extendToString(StringBuffer buffer)
+   {
+      buffer.append(getName());
+   }
+
+   /**
+    * Returns a <code>ClassPool</code> for this class.
+    */
+   public ClassPool getClassPool()
+   {
+      return null;
+   }
+
+   /**
+    * Returns a class file for this class.
+    * <p/>
+    * <p>This method is not available if <code>isFrozen()</code>
+    * is true.
+    */
+   public ClassFile getClassFile()
+   {
+      checkModify();
+      return getClassFile2();
+   }
+
+   /**
+    * Undocumented method.  Do not use; internal-use only.
+    */
+   public ClassFile getClassFile2()
+   {
+      return null;
+   }
+
+   /**
+    * Undocumented method.  Do not use; internal-use only.
+    */
+   public javassist.compiler.AccessorMaker getAccessorMaker()
+   {
+      return null;
+   }
+
+   /**
+    * Returns the uniform resource locator (URL) of the class file.
+    */
+   public URL getURL() throws NotFoundException
+   {
+      throw new NotFoundException(getName());
+   }
+
+   /**
+    * Returns true if the definition of the class has been modified.
+    */
+   public boolean isModified()
+   {
+      return false;
+   }
+
+   /**
+    * Returns true if the class has been loaded or written out
+    * and thus it cannot be modified any more.
+    *
+    * @see #defrost()
+    */
+   public boolean isFrozen()
+   {
+      return true;
+   }
+
+   void freeze()
+   {
+   }
+
+   void checkModify() throws RuntimeException
+   {
+      if (isFrozen())
+         throw new RuntimeException(getName() + " class is frozen");
+
+      // isModified() must return true after this method is invoked.
+   }
+
+   /**
+    * Defrosts the class so that the class can be modified again.
+    * <p/>
+    * <p>To avoid changes that will be never reflected,
+    * the class is frozen to be unmodifiable if it is loaded or
+    * written out.  This method should be called only in a case
+    * that the class will be reloaded or written out later again.
+    * <p/>
+    * <p>If <code>defrost()</code> will be called later, pruning
+    * must be disallowed in advance.
+    *
+    * @see #isFrozen()
+    * @see #stopPruning(boolean)
+    */
+   public void defrost()
+   {
+      throw new RuntimeException("cannot defrost " + getName());
+   }
+
+   /**
+    * Disallows (or allows) pruning the data structure on memory
+    * when this <code>CtClass</code> object is converted into a class file.
+    * Pruning saves memory space since a <code>ClassPool</code> holds
+    * all instances of <code>CtClass</code>
+    * all the time of program execution.
+    * However, pruning discards the data representing part of the
+    * class definition, such as method bodies.
+    * Therefore, once it is pruned, <code>toBytecode()</code>,
+    * <code>writeFile()</code>, or <code>toClass()</code> cannot
+    * be called again.
+    * <p/>
+    * <p>Initially, pruning is allowed.
+    *
+    * @param stop disallow pruning if true.  Otherwise, allow.
+    * @see #detach()
+    * @see #toBytecode()
+    * @see #toClass()
+    * @see #writeFile()
+    */
+   public void stopPruning(boolean stop)
+   {
+   }
+
+   /* Called by get() in ClassPool.
+    * CtClassType overrides this method.
+    */
+   void incGetCounter()
+   {
+   }
+
+   /**
+    * Returns <code>true</code> if this object represents a primitive
+    * Java type: boolean, byte, char, short, int, long, float, double,
+    * or void.
+    */
+   public boolean isPrimitive()
+   {
+      return false;
+   }
+
+   /**
+    * Returns <code>true</code> if this object represents an array type.
+    */
+   public boolean isArray()
+   {
+      return false;
+   }
+
+   /**
+    * If this object represents an array, this method returns the component
+    * type of the array.  Otherwise, it returns <code>null</code>.
+    */
+   public CtClass getComponentType() throws NotFoundException
+   {
+      return null;
+   }
+
+   /**
+    * Returns <code>true</code> if this class extends or implements
+    * <code>clazz</code>.  It also returns <code>true</code> if
+    * this class is the same as <code>clazz</code>.
+    */
+   public boolean subtypeOf(CtClass clazz) throws NotFoundException
+   {
+      return this == clazz || getName().equals(clazz.getName());
+   }
+
+   /**
+    * Obtains the fully-qualified name of the class.
+    */
+   public String getName()
+   {
+      return qualifiedName;
+   }
+
+   /**
+    * Obtains the not-qualified class name.
+    */
+   public final String getSimpleName()
+   {
+      String qname = qualifiedName;
+      int index = qname.lastIndexOf('.');
+      if (index < 0)
+         return qname;
+      else
+         return qname.substring(index + 1);
+   }
+
+   /**
+    * Obtains the package name.  It may be <code>null</code>.
+    */
+   public final String getPackageName()
+   {
+      String qname = qualifiedName;
+      int index = qname.lastIndexOf('.');
+      if (index < 0)
+         return null;
+      else
+         return qname.substring(0, index);
+   }
+
+   /**
+    * Sets the class name
+    *
+    * @param name fully-qualified name
+    */
+   public void setName(String name)
+   {
+      checkModify();
+      if (name != null)
+         qualifiedName = name;
+   }
+
+   /**
+    * Substitutes <code>newName</code> for all occurrences of a class
+    * name <code>oldName</code> in the class file.
+    *
+    * @param oldName replaced class name
+    * @param newName substituted class name
+    */
+   public void replaceClassName(String oldName, String newName)
+   {
+      checkModify();
+   }
+
+   /**
+    * Changes class names appearing in the class file according to the
+    * given <code>map</code>.
+    * <p/>
+    * <p>All the class names appearing in the class file are tested
+    * with <code>map</code> to determine whether each class name is
+    * replaced or not.  Thus this method can be used for collecting
+    * all the class names in the class file.  To do that, first define
+    * a subclass of <code>ClassMap</code> so that <code>get()</code>
+    * records all the given parameters.  Then, make an instance of
+    * that subclass as an empty hash-table.  Finally, pass that instance
+    * to this method.  After this method finishes, that instance would
+    * contain all the class names appearing in the class file.
+    *
+    * @param map the hashtable associating replaced class names
+    *            with substituted names.
+    */
+   public void replaceClassName(ClassMap map)
+   {
+      checkModify();
+   }
+
+   /**
+    * Returns a collection of the names of all the classes
+    * referenced in this class.
+    * That collection includes the name of this class.
+    * <p/>
+    * <p>This method may return <code>null</code>.
+    */
+   public Collection getRefClasses()
+   {
+      ClassFile cf = getClassFile2();
+      if (cf != null)
+      {
+         ClassMap cm = new ClassMap()
+         {
+            public void put(String oldname, String newname)
+            {
+               put0(oldname, newname);
+            }
+
+            public Object get(Object jvmClassName)
+            {
+               String n = toJavaName((String) jvmClassName);
+               put0(n, n);
+               return null;
+            }
+
+            public void fix(String name)
+            {
+            }
+         };
+         cf.renameClass(cm);
+         return cm.values();
+      }
+      else
+         return null;
+   }
+
+   /**
+    * Determines whether this object represents a class or an interface.
+    * It returns <code>true</code> if this object represents an interface.
+    */
+   public boolean isInterface()
+   {
+      return false;
+   }
+
+   /**
+    * Returns the modifiers for this class, encoded in an integer.
+    * For decoding, use <code>javassist.Modifier</code>.
+    *
+    * @see Modifier
+    */
+   public int getModifiers()
+   {
+      return 0;
+   }
+
+   /**
+    * Sets the modifiers.
+    *
+    * @param mod modifiers encoded by
+    *            <code>javassist.Modifier</code>
+    * @see Modifier
+    */
+   public void setModifiers(int mod)
+   {
+      checkModify();
+   }
+
+   /**
+    * Determines whether the class directly or indirectly extends
+    * the given class.  If this class extends a class A and
+    * the class A extends a class B, then subclassof(B) returns true.
+    * <p/>
+    * <p>This method returns true if the given class is identical to
+    * the class represented by this object.
+    */
+   public boolean subclassOf(CtClass superclass)
+   {
+      return false;
+   }
+
+   /**
+    * Obtains the class object representing the superclass of the
+    * class.
+    * It returns null if this object represents the
+    * <code>java.lang.Object</code> class and thus it does not have
+    * the super class.
+    * <p/>
+    * <p>If this object represents an interface, this method
+    * always returns the <code>java.lang.Object</code> class.
+    * To obtain the super interfaces
+    * extended by that interface, call <code>getInterfaces()</code>.
+    */
+   public CtClass getSuperclass() throws NotFoundException
+   {
+      return null;
+   }
+
+   /**
+    * Changes a super class unless this object represents an interface.
+    * The new super class must be compatible with the old one.
+    * <p/>
+    * <p>If this object represents an interface, this method is equivalent
+    * to <code>addInterface()</code>; it appends <code>clazz</code> to
+    * the list of the super interfaces extended by that interface.
+    * Note that an interface can extend multiple super interfaces.
+    */
+   public void setSuperclass(CtClass clazz) throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Obtains the class objects representing the interfaces implemented
+    * by the class or, if this object represents an interface, the interfaces
+    * extended by that interface.
+    */
+   public CtClass[] getInterfaces() throws NotFoundException
+   {
+      return new CtClass[0];
+   }
+
+   /**
+    * Sets implemented interfaces.  If this object represents an interface,
+    * this method sets the interfaces extended by that interface.
+    *
+    * @param list a list of the <code>CtClass</code> objects
+    *             representing interfaces, or
+    *             <code>null</code> if the class implements
+    *             no interfaces.
+    */
+   public void setInterfaces(CtClass[] list)
+   {
+      checkModify();
+   }
+
+   /**
+    * Adds an interface.
+    *
+    * @param anInterface the added interface.
+    */
+   public void addInterface(CtClass anInterface)
+   {
+      checkModify();
+   }
+
+   /**
+    * If this class is a member class or interface of another class,
+    * then the class enclosing this class is returned.
+    *
+    * @return null if this class is a top-level class.
+    */
+   public CtClass getDeclaringClass() throws NotFoundException
+   {
+      return null;
+   }
+
+   /**
+    * Makes a new nested class.  Making a nested class modifies the
+    * data in this <code>CtClass</code>.
+    * <p/>
+    * <p>The current implementation only supports a static nested class.
+    * <code>isStatic</code> must be true.
+    *
+    * @param name     the simple name of the nested class.
+    * @param isStatic true if the nested class is static.
+    */
+   public CtClass makeNestedClass(String name, boolean isStatic)
+   {
+      throw new RuntimeException(getName() + " is not a class");
+   }
+
+   /**
+    * Returns an array containing <code>CtField</code> objects
+    * representing all the public fields of the class.
+    * That array includes public fields inherited from the
+    * superclasses.
+    */
+   public CtField[] getFields()
+   {
+      return new CtField[0];
+   }
+
+   /**
+    * Returns the field with the specified name.  The returned field
+    * may be a private field declared in a super class or interface.
+    */
+   public CtField getField(String name) throws NotFoundException
+   {
+      throw new NotFoundException(name);
+   }
+
+   /**
+    * @return null     if the specified field is not found.
+    */
+   CtField getField2(String name)
+   {
+      return null;
+   }
+
+   /**
+    * Gets all the fields declared in the class.  The inherited fields
+    * are not included.
+    * <p/>
+    * <p>Note: the result does not include inherited fields.
+    */
+   public CtField[] getDeclaredFields()
+   {
+      return new CtField[0];
+   }
+
+   /**
+    * Retrieves the field with the specified name among the fields
+    * declared in the class.
+    * <p/>
+    * <p>Note: this method does not search the superclasses.
+    */
+   public CtField getDeclaredField(String name) throws NotFoundException
+   {
+      throw new NotFoundException(name);
+   }
+
+   /**
+    * Gets all the constructors and methods declared in the class.
+    */
+   public CtBehavior[] getDeclaredBehaviors()
+   {
+      return new CtBehavior[0];
+   }
+
+   /**
+    * Returns an array containing <code>CtConstructor</code> objects
+    * representing all the public constructors of the class.
+    */
+   public CtConstructor[] getConstructors()
+   {
+      return new CtConstructor[0];
+   }
+
+   /**
+    * Returns the constructor with the given signature,
+    * which is represented by a character string
+    * called method descriptor.
+    * For details of the method descriptor, see the JVM specification
+    * or <code>javassist.bytecode.Descriptor</code>.
+    *
+    * @param desc method descriptor
+    * @see javassist.bytecode.Descriptor
+    */
+   public CtConstructor getConstructor(String desc)
+           throws NotFoundException
+   {
+      throw new NotFoundException("no such a constructor");
+   }
+
+   /**
+    * Gets all the constructors declared in the class.
+    *
+    * @see javassist.CtConstructor
+    */
+   public CtConstructor[] getDeclaredConstructors()
+   {
+      return new CtConstructor[0];
+   }
+
+   /**
+    * Returns a constructor receiving the specified parameters.
+    *
+    * @param params parameter types.
+    */
+   public CtConstructor getDeclaredConstructor(CtClass[] params)
+           throws NotFoundException
+   {
+      String desc = Descriptor.ofConstructor(params);
+      return getConstructor(desc);
+   }
+
+   /**
+    * Gets the class initializer (static constructor)
+    * declared in the class.
+    * This method returns <code>null</code> if
+    * no class initializer is not declared.
+    *
+    * @see #makeClassInitializer()
+    * @see javassist.CtConstructor
+    */
+   public CtConstructor getClassInitializer()
+   {
+      return null;
+   }
+
+   /**
+    * Returns an array containing <code>CtMethod</code> objects
+    * representing all the public methods of the class.
+    * That array includes public methods inherited from the
+    * superclasses.
+    */
+   public CtMethod[] getMethods()
+   {
+      return new CtMethod[0];
+   }
+
+   /**
+    * Returns the method with the given name and signature.
+    * The returned method may be declared in a super class.
+    * The method signature is represented by a character string
+    * called method descriptor,
+    * which is defined in the JVM specification.
+    *
+    * @param name method name
+    * @param desc method descriptor
+    * @see javassist.bytecode.Descriptor
+    */
+   public CtMethod getMethod(String name, String desc)
+           throws NotFoundException
+   {
+      throw new NotFoundException(name);
+   }
+
+   /**
+    * Gets all methods declared in the class.  The inherited methods
+    * are not included.
+    *
+    * @see javassist.CtMethod
+    */
+   public CtMethod[] getDeclaredMethods()
+   {
+      return new CtMethod[0];
+   }
+
+   /**
+    * Retrieves the method with the specified name and parameter types
+    * among the methods declared in the class.
+    * <p/>
+    * <p>Note: this method does not search the superclasses.
+    *
+    * @param name   method name
+    * @param params parameter types
+    * @see javassist.CtMethod
+    */
+   public CtMethod getDeclaredMethod(String name, CtClass[] params)
+           throws NotFoundException
+   {
+      throw new NotFoundException(name);
+   }
+
+   /**
+    * Retrieves the method with the specified name among the methods
+    * declared in the class.  If there are multiple methods with
+    * the specified name, then this method returns one of them.
+    * <p/>
+    * <p>Note: this method does not search the superclasses.
+    *
+    * @see javassist.CtMethod
+    */
+   public CtMethod getDeclaredMethod(String name) throws NotFoundException
+   {
+      throw new NotFoundException(name);
+   }
+
+   /**
+    * Makes an empty class initializer (static constructor).
+    * If the class already includes a class initializer,
+    * this method returns it.
+    *
+    * @see #getClassInitializer()
+    */
+   public CtConstructor makeClassInitializer()
+           throws CannotCompileException
+   {
+      throw new CannotCompileException("not a class");
+   }
+
+   /**
+    * Adds a constructor.  To add a class initializer (static constructor),
+    * call <code>makeClassInitializer()</code>.
+    *
+    * @see #makeClassInitializer()
+    */
+   public void addConstructor(CtConstructor c)
+           throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Adds a method.
+    */
+   public void addMethod(CtMethod m) throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Adds a field.
+    * <p/>
+    * <p>The <code>CtField</code> belonging to another
+    * <code>CtClass</code> cannot be directly added to this class.
+    * Only a field created for this class can be added.
+    *
+    * @see javassist.CtField#CtField(CtField,CtClass)
+    */
+   public void addField(CtField f) throws CannotCompileException
+   {
+      addField(f, (CtField.Initializer) null);
+   }
+
+   /**
+    * Adds a field with an initial value.
+    * <p/>
+    * <p>The <code>CtField</code> belonging to another
+    * <code>CtClass</code> cannot be directly added to this class.
+    * Only a field created for this class can be added.
+    * <p/>
+    * <p>The initial value is given as an expression written in Java.
+    * Any regular Java expression can be used for specifying the initial
+    * value.  The followings are examples.
+    * <p/>
+    * <ul><pre>
+    * cc.addField(f, "0")               // the initial value is 0.
+    * cc.addField(f, "i + 1")           // i + 1.
+    * cc.addField(f, "new Point()");    // a Point object.
+    * </pre></ul>
+    * <p/>
+    * <p>Here, the type of variable <code>cc</code> is <code>CtClass</code>.
+    * The type of <code>f</code> is <code>CtField</code>.
+    *
+    * @param init an expression for the initial value.
+    * @see javassist.CtField.Initializer#byExpr(String)
+    * @see javassist.CtField#CtField(CtField,CtClass)
+    */
+   public void addField(CtField f, String init)
+           throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Adds a field with an initial value.
+    * <p/>
+    * <p>The <code>CtField</code> belonging to another
+    * <code>CtClass</code> cannot be directly added to this class.
+    * Only a field created for this class can be added.
+    * <p/>
+    * <p>For example,
+    * <p/>
+    * <ul><pre>
+    * CtClass cc = ...;
+    * addField(new CtField(CtClass.intType, "i", cc),
+    *          CtField.Initializer.constant(1));
+    * </pre></ul>
+    * <p/>
+    * <p>This code adds an <code>int</code> field named "i".  The
+    * initial value of this field is 1.
+    *
+    * @param init specifies the initial value of the field.
+    * @see javassist.CtField#CtField(CtField,CtClass)
+    */
+   public void addField(CtField f, CtField.Initializer init)
+           throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Obtains an attribute with the given name.
+    * If that attribute is not found in the class file, this
+    * method returns null.
+    * <p/>
+    * <p>This is a convenient method mainly for obtaining
+    * a user-defined attribute.  For dealing with attributes, see the
+    * <code>javassist.bytecode</code> package.  For example, the following
+    * expression returns all the attributes of a class file.
+    * <p/>
+    * <ul><pre>
+    * getClassFile().getAttributes()
+    * </pre></ul>
+    *
+    * @param name attribute name
+    * @see javassist.bytecode.AttributeInfo
+    */
+   public byte[] getAttribute(String name)
+   {
+      return null;
+   }
+
+   /**
+    * Adds a named attribute.
+    * An arbitrary data (smaller than 64Kb) can be saved in the class
+    * file.  Some attribute name are reserved by the JVM.
+    * The attributes with the non-reserved names are ignored when a
+    * class file is loaded into the JVM.
+    * If there is already an attribute with
+    * the same name, this method substitutes the new one for it.
+    * <p/>
+    * <p>This is a convenient method mainly for adding
+    * a user-defined attribute.  For dealing with attributes, see the
+    * <code>javassist.bytecode</code> package.  For example, the following
+    * expression adds an attribute of a class file.
+    * <p/>
+    * <ul><pre>
+    * getClassFile().addAttribute(info)
+    * </pre></ul>
+    *
+    * @param name attribute name
+    * @param data attribute value
+    * @see javassist.bytecode.AttributeInfo
+    */
+   public void setAttribute(String name, byte[] data)
+   {
+      checkModify();
+   }
+
+   /**
+    * Applies the given converter to all methods and constructors
+    * declared in the class.  This method calls <code>instrument()</code>
+    * on every <code>CtMethod</code> and <code>CtConstructor</code> object
+    * in the class.
+    *
+    * @param converter specifies how to modify.
+    */
+   public void instrument(CodeConverter converter)
+           throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Modifies the bodies of all methods and constructors
+    * declared in the class.  This method calls <code>instrument()</code>
+    * on every <code>CtMethod</code> and <code>CtConstructor</code> object
+    * in the class.
+    *
+    * @param editor specifies how to modify.
+    */
+   public void instrument(ExprEditor editor)
+           throws CannotCompileException
+   {
+      checkModify();
+   }
+
+   /**
+    * Converts this class to a <code>java.lang.Class</code> object.
+    * Once this method is called, further modifications are not
+    * allowed any more.
+    * To load the class, this method uses the context class loader
+    * of the current thread.  If the program is running on some application
+    * server, the context class loader might be inappropriate to load the
+    * class.
+    * <p/>
+    * <p>This method is provided for convenience.  If you need more
+    * complex functionality, you should write your own class loader.
+    *
+    * @see #toClass(java.lang.ClassLoader)
+    */
+   public Class toClass()
+           throws CannotCompileException
+   {
+      return getClassPool().toClass(this, Thread.currentThread().getContextClassLoader());
+   }
+
+   /**
+    * Converts this class to a <code>java.lang.Class</code> object.
+    * Once this method is called, further modifications are not allowed
+    * any more.
+    * <p/>
+    * <p>The class file represented by this <code>CtClass</code> is
+    * loaded by the given class loader to construct a
+    * <code>java.lang.Class</code> object.  Since a private method
+    * on the class loader is invoked through the reflection API,
+    * the caller must have permissions to do that.
+    * <p/>
+    * <p>This method is provided for convenience.  If you need more
+    * complex functionality, you should write your own class loader.
+    *
+    * @param loader the class loader used to load this class.
+    */
+   public Class toClass(ClassLoader loader)
+           throws CannotCompileException
+   {
+      return getClassPool().toClass(this, loader);
+   }
+
+   /**
+    * Removes this <code>CtClass</code> object from the
+    * <code>ClassPool</code>.
+    * After this method is called, any method cannot be called on the
+    * removed <code>CtClass</code> object.
+    * <p/>
+    * <p>If <code>get()</code> in <code>ClassPool</code> is called
+    * with the name of the removed method,
+    * the <code>ClassPool</code> will read the class file again
+    * and constructs another <code>CtClass</code> object representing
+    * the same class.
+    */
+   public void detach()
+   {
+      ClassPool cp = getClassPool();
+      CtClass obj = cp.removeCached(getName());
+      if (obj != this)
+         cp.cacheCtClass(getName(), obj);
+   }
+
+   /**
+    * Converts this class to a class file.
+    * Once this method is called, further modifications are not
+    * possible any more.
+    *
+    * @return the contents of the class file.
+    */
+   public byte[] toBytecode()
+           throws IOException, CannotCompileException
+   {
+      ByteArrayOutputStream barray = new ByteArrayOutputStream();
+      DataOutputStream out = new DataOutputStream(barray);
+      try
+      {
+         toBytecode(out);
+      }
+      finally
+      {
+         out.close();
+      }
+
+      return barray.toByteArray();
+   }
+
+   /**
+    * Writes a class file represented by this <code>CtClass</code>
+    * object in the current directory.
+    * Once this method is called, further modifications are not
+    * possible any more.
+    */
+   public void writeFile()
+           throws NotFoundException, IOException, CannotCompileException
+   {
+      writeFile(".");
+   }
+
+   /**
+    * Writes a class file represented by this <code>CtClass</code>
+    * object on a local disk.
+    * Once this method is called, further modifications are not
+    * possible any more.
+    *
+    * @param directoryName it must end without a directory separator.
+    */
+   public void writeFile(String directoryName)
+           throws NotFoundException, CannotCompileException, IOException
+   {
+      String classname = getName();
+      String filename = directoryName + File.separatorChar
+              + classname.replace('.', File.separatorChar) + ".class";
+      int pos = filename.lastIndexOf(File.separatorChar);
+      if (pos > 0)
+      {
+         String dir = filename.substring(0, pos);
+         if (!dir.equals("."))
+            new File(dir).mkdirs();
+      }
+
+      DataOutputStream out
+              = new DataOutputStream(new BufferedOutputStream(new DelayedFileOutputStream(filename)));
+      try
+      {
+         toBytecode(out);
+      }
+      finally
+      {
+         out.close();
+      }
+   }
+
+   static class DelayedFileOutputStream extends OutputStream
+   {
+      private FileOutputStream file;
+      private String filename;
+
+      DelayedFileOutputStream(String name)
+      {
+         file = null;
+         filename = name;
+      }
+
+      private void init() throws IOException
+      {
+         if (file == null)
+            file = new FileOutputStream(filename);
+      }
+
+      public void write(int b) throws IOException
+      {
+         init();
+         file.write(b);
+      }
+
+      public void write(byte[] b) throws IOException
+      {
+         init();
+         file.write(b);
+      }
+
+      public void write(byte[] b, int off, int len) throws IOException
+      {
+         init();
+         file.write(b, off, len);
+
+      }
+
+      public void flush() throws IOException
+      {
+         init();
+         file.flush();
+      }
+
+      public void close() throws IOException
+      {
+         init();
+         file.close();
+      }
+   }
+
+   /**
+    * Converts this class to a class file.
+    * Once this method is called, further modifications are not
+    * possible any more.
+    * <p/>
+    * <p>This method dose not close the output stream in the end.
+    *
+    * @param out the output stream that a class file is written to.
+    */
+   public void toBytecode(DataOutputStream out)
+           throws CannotCompileException, IOException
+   {
+      throw new CannotCompileException("not a class");
+   }
 }
index cda8fd36f10b09319590cd371638f77c94b1a7f8..177f772db473033966aec9bc81a7c05bf07dd1ee 100644 (file)
 
 package javassist;
 
-import javassist.bytecode.*;
-import javassist.compiler.Javac;
-import javassist.compiler.CompileError;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.AttributeInfo;
+import javassist.bytecode.BadBytecode;
+import javassist.bytecode.Bytecode;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.CodeAttribute;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.FieldInfo;
+import javassist.bytecode.InnerClassesAttribute;
+import javassist.bytecode.MethodInfo;
 import javassist.compiler.AccessorMaker;
+import javassist.compiler.CompileError;
+import javassist.compiler.Javac;
 import javassist.expr.ExprEditor;
-import java.io.InputStream;
+
 import java.io.BufferedInputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
-import java.util.Enumeration;
 import java.util.List;
 
 /**
  * Class types.
  */
-class CtClassType extends CtClass {
-    ClassPool classPool;
-    boolean wasChanged;
-    private boolean wasFrozen;
-    boolean wasPruned;
-    ClassFile classfile;
-
-    private CtField fieldsCache;
-    private CtConstructor constructorsCache;
-    private CtConstructor classInitializerCache;
-    private CtMethod methodsCache;
-
-    private AccessorMaker accessors;
-
-    private FieldInitLink fieldInitializers;
-    private Hashtable hiddenMethods;    // must be synchronous
-    private int uniqueNumberSeed;
-
-    private boolean doPruning = true;
-    int getCounter;
-    private static int readCounter = 0;
-    private static final int READ_THRESHOLD = 100;  // see getClassFile2()
-
-    CtClassType(String name, ClassPool cp) {
-        super(name);
-        classPool = cp;
-        wasChanged = wasFrozen = wasPruned = false;
-        classfile = null;
-        accessors = null;
-        fieldInitializers = null;
-        hiddenMethods = null;
-        uniqueNumberSeed = 0;
-        eraseCache();
-        getCounter = 0;
-    }
-
-    CtClassType(InputStream ins, ClassPool cp) throws IOException {
-        this((String)null, cp);
-        classfile = new ClassFile(new DataInputStream(ins));
-        qualifiedName = classfile.getName();
-    }
-
-    protected void extendToString(StringBuffer buffer) {
-        if (wasChanged)
-            buffer.append("changed ");
-
-        if (wasFrozen)
-            buffer.append("frozen ");          
-
-        if (wasPruned)
-            buffer.append("pruned ");
-
-        buffer.append(Modifier.toString(getModifiers()));
-        buffer.append(" class ");
-        buffer.append(getName());
-
-        try {
-            CtClass ext = getSuperclass();
-            if (ext != null) {
-                String name =ext.getName();
-                if (!name.equals("java.lang.Object"))
-                    buffer.append(" extends " + ext.getName());
-            }
-        }
-        catch (NotFoundException e) {
-            buffer.append(" extends ??");
-        }
-
-        try {
-            CtClass[] intf = getInterfaces();
-            if (intf.length > 0)
-                buffer.append(" implements ");
-
-            for (int i = 0; i < intf.length; ++i) {
-                buffer.append(intf[i].getName());
-                buffer.append(", ");
-            }            
-        }
-        catch (NotFoundException e) {
-            buffer.append(" extends ??");
-        }
-
-        CtField field = getFieldsCache();
-        buffer.append(" fields=");
-        while (field != null) {
-            buffer.append(field);
-            buffer.append(", ");
-            field = field.next;
-        }
-
-        CtConstructor c = getConstructorsCache();
-        buffer.append(" constructors=");
-        while (c != null) {
-            buffer.append(c);
+class CtClassType extends CtClass
+{
+   ClassPool classPool;
+   boolean wasChanged;
+   private boolean wasFrozen;
+   boolean wasPruned;
+   ClassFile classfile;
+
+   private CtField fieldsCache;
+   private CtConstructor constructorsCache;
+   private CtConstructor classInitializerCache;
+   private CtMethod methodsCache;
+
+   private AccessorMaker accessors;
+
+   private FieldInitLink fieldInitializers;
+   private Hashtable hiddenMethods;    // must be synchronous
+   private int uniqueNumberSeed;
+
+   private boolean doPruning = false;
+   int getCounter;
+   private static int readCounter = 0;
+   private static final int READ_THRESHOLD = 100;  // see getClassFile2()
+
+   CtClassType(String name, ClassPool cp)
+   {
+      super(name);
+      classPool = cp;
+      wasChanged = wasFrozen = wasPruned = false;
+      classfile = null;
+      accessors = null;
+      fieldInitializers = null;
+      hiddenMethods = null;
+      uniqueNumberSeed = 0;
+      eraseCache();
+      getCounter = 0;
+   }
+
+   CtClassType(InputStream ins, ClassPool cp) throws IOException
+   {
+      this((String) null, cp);
+      classfile = new ClassFile(new DataInputStream(ins));
+      qualifiedName = classfile.getName();
+   }
+
+   protected void extendToString(StringBuffer buffer)
+   {
+      if (wasChanged)
+         buffer.append("changed ");
+
+      if (wasFrozen)
+         buffer.append("frozen ");
+
+      if (wasPruned)
+         buffer.append("pruned ");
+
+      buffer.append(Modifier.toString(getModifiers()));
+      buffer.append(" class ");
+      buffer.append(getName());
+
+      try
+      {
+         CtClass ext = getSuperclass();
+         if (ext != null)
+         {
+            String name = ext.getName();
+            if (!name.equals("java.lang.Object"))
+               buffer.append(" extends " + ext.getName());
+         }
+      }
+      catch (NotFoundException e)
+      {
+         buffer.append(" extends ??");
+      }
+
+      try
+      {
+         CtClass[] intf = getInterfaces();
+         if (intf.length > 0)
+            buffer.append(" implements ");
+
+         for (int i = 0; i < intf.length; ++i)
+         {
+            buffer.append(intf[i].getName());
             buffer.append(", ");
-            c = c.next;
-        }
-
-        CtMethod m = getMethodsCache();
-        buffer.append(" methods=");
-        while (m != null) {
-            buffer.append(m);
-            buffer.append(", ");
-            m = m.next;
-        }
-    }
-
-    protected void eraseCache() {
-        fieldsCache = null;
-        constructorsCache = null;
-        classInitializerCache = null;
-        methodsCache = null;
-    }
-
-    public AccessorMaker getAccessorMaker() {
-        if (accessors == null)
-            accessors = new AccessorMaker(this);
-
-        return accessors;
-    }
-
-    public ClassFile getClassFile2() {
-        if (classfile != null)
-            return classfile;
-
-        if (readCounter++ > READ_THRESHOLD) {
-            doCompaction();
-            readCounter = 0;
-        }
-
-        InputStream fin = null;
-        try {
-            fin = classPool.openClassfile(getName());
-            if (fin == null)
-                throw new NotFoundException(getName());
-
-            fin = new BufferedInputStream(fin);
-            classfile = new ClassFile(new DataInputStream(fin));
-            return classfile;
-        }
-        catch (NotFoundException e) {
-            throw new RuntimeException(e.toString());
-        }
-        catch (IOException e) {
-            throw new RuntimeException(e.toString());
-        }
-        finally {
-            if (fin != null)
-                try {
-                    fin.close();
-                }
-                catch (IOException e) {}
-        }
-    }
-
-    /* Inherited from CtClass.  Called by get() in ClassPool.
-     *
-     * @see javassist.CtClass#incGetCounter()
-     */
-    void incGetCounter() { ++getCounter; }
-
-    private void doCompaction() {
-        Enumeration e = classPool.classes.elements();
-        while (e.hasMoreElements()) {
-            Object obj = e.nextElement();
-            if (obj instanceof CtClassType) {
-                CtClassType cct = (CtClassType)obj;
-                if (cct.getCounter < 2 && !cct.isModified()) {
-                    cct.eraseCache();
-                    cct.classfile = null;
-                }
-
-                cct.getCounter = 0;
-            }
-        }
-    }
-
-    public ClassPool getClassPool() { return classPool; }
-
-    void setClassPool(ClassPool cp) { classPool = cp; }
-
-    public URL getURL() throws NotFoundException {
-        URL url = classPool.find(getName());
-        if (url == null)
+         }
+      }
+      catch (NotFoundException e)
+      {
+         buffer.append(" extends ??");
+      }
+
+      CtField field = getFieldsCache();
+      buffer.append(" fields=");
+      while (field != null)
+      {
+         buffer.append(field);
+         buffer.append(", ");
+         field = field.next;
+      }
+
+      CtConstructor c = getConstructorsCache();
+      buffer.append(" constructors=");
+      while (c != null)
+      {
+         buffer.append(c);
+         buffer.append(", ");
+         c = c.next;
+      }
+
+      CtMethod m = getMethodsCache();
+      buffer.append(" methods=");
+      while (m != null)
+      {
+         buffer.append(m);
+         buffer.append(", ");
+         m = m.next;
+      }
+   }
+
+   protected void eraseCache()
+   {
+      fieldsCache = null;
+      constructorsCache = null;
+      classInitializerCache = null;
+      methodsCache = null;
+   }
+
+   public AccessorMaker getAccessorMaker()
+   {
+      if (accessors == null)
+         accessors = new AccessorMaker(this);
+
+      return accessors;
+   }
+
+   public ClassFile getClassFile2()
+   {
+      if (classfile != null)
+         return classfile;
+
+      if (readCounter++ > READ_THRESHOLD)
+      {
+         doCompaction();
+         readCounter = 0;
+      }
+
+      InputStream fin = null;
+      try
+      {
+         fin = classPool.openClassfile(getName());
+         if (fin == null)
             throw new NotFoundException(getName());
-        else
-            return url;
-    }
-
-    public boolean isModified() { return wasChanged; }
-
-    public boolean isFrozen() { return wasFrozen; }
-
-    void freeze() { wasFrozen = true; }
-
-    void checkModify() throws RuntimeException {
-        super.checkModify();
-        wasChanged = true;
-    }
 
-    public void defrost() {
-        checkPruned("defrost");
-        wasFrozen = false;
-    }
-
-    public boolean subtypeOf(CtClass clazz) throws NotFoundException {
-        int i;
-        String cname = clazz.getName();
-        if (this == clazz || getName().equals(cname))
-            return true;
+         fin = new BufferedInputStream(fin);
+         classfile = new ClassFile(new DataInputStream(fin));
+         return classfile;
+      }
+      catch (NotFoundException e)
+      {
+         throw new RuntimeException(e.toString());
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e.toString());
+      }
+      finally
+      {
+         if (fin != null)
+            try
+            {
+               fin.close();
+            }
+            catch (IOException e)
+            {
+            }
+      }
+   }
+
+   /* Inherited from CtClass.  Called by get() in ClassPool.
+    *
+    * @see javassist.CtClass#incGetCounter()
+    */
+   void incGetCounter()
+   {
+      ++getCounter;
+   }
+
+   private void doCompaction()
+   {
+      Enumeration e = classPool.classes.elements();
+      while (e.hasMoreElements())
+      {
+         Object obj = e.nextElement();
+         if (obj instanceof CtClassType)
+         {
+            CtClassType cct = (CtClassType) obj;
+            if (cct.getCounter < 2 && !cct.isModified())
+            {
+               cct.eraseCache();
+               cct.classfile = null;
+            }
 
-        ClassFile file = getClassFile2();
-        String supername = file.getSuperclass();
-        if (supername != null && supername.equals(cname))
+            cct.getCounter = 0;
+         }
+      }
+   }
+
+   public ClassPool getClassPool()
+   {
+      return classPool;
+   }
+
+   void setClassPool(ClassPool cp)
+   {
+      classPool = cp;
+   }
+
+   public URL getURL() throws NotFoundException
+   {
+      URL url = classPool.find(getName());
+      if (url == null)
+         throw new NotFoundException(getName());
+      else
+         return url;
+   }
+
+   public boolean isModified()
+   {
+      return wasChanged;
+   }
+
+   public boolean isFrozen()
+   {
+      return wasFrozen;
+   }
+
+   void freeze()
+   {
+      wasFrozen = true;
+   }
+
+   void checkModify() throws RuntimeException
+   {
+      super.checkModify();
+      wasChanged = true;
+   }
+
+   public void defrost()
+   {
+      checkPruned("defrost");
+      wasFrozen = false;
+   }
+
+   public boolean subtypeOf(CtClass clazz) throws NotFoundException
+   {
+      int i;
+      String cname = clazz.getName();
+      if (this == clazz || getName().equals(cname))
+         return true;
+
+      ClassFile file = getClassFile2();
+      String supername = file.getSuperclass();
+      if (supername != null && supername.equals(cname))
+         return true;
+
+      String[] ifs = file.getInterfaces();
+      int num = ifs.length;
+      for (i = 0; i < num; ++i)
+         if (ifs[i].equals(cname))
             return true;
 
-        String[] ifs = file.getInterfaces();
-        int num = ifs.length;
-        for (i = 0; i < num; ++i)
-            if (ifs[i].equals(cname))
-                return true;
+      if (supername != null && classPool.get(supername).subtypeOf(clazz))
+         return true;
 
-        if (supername != null && classPool.get(supername).subtypeOf(clazz))
+      for (i = 0; i < num; ++i)
+         if (classPool.get(ifs[i]).subtypeOf(clazz))
             return true;
 
-        for (i = 0; i < num; ++i)
-            if (classPool.get(ifs[i]).subtypeOf(clazz))
-                return true;
-
-        return false;
-    }
-
-    public void setName(String name) throws RuntimeException {
-        String oldname = getName();
-        if (name.equals(oldname))
-            return;
-
-        // check this in advance although classNameChanged() below does.
-        classPool.checkNotFrozen(name);
-        ClassFile cf = getClassFile2();
-        super.setName(name);
-        cf.setName(name);
-        eraseCache();
-        classPool.classNameChanged(oldname, this);
-    }
-
-    public void replaceClassName(ClassMap classnames)
-        throws RuntimeException 
-    {
-        String oldClassName = getName();
-        String newClassName
-            = (String)classnames.get(Descriptor.toJvmName(oldClassName));
-        if (newClassName != null) {
-            newClassName = Descriptor.toJavaName(newClassName);
-            // check this in advance although classNameChanged() below does.
-            classPool.checkNotFrozen(newClassName);
-        }
-
-        super.replaceClassName(classnames);
-        ClassFile cf = getClassFile2();
-        cf.renameClass(classnames);
-        eraseCache();
-
-        if (newClassName != null) {
-            super.setName(newClassName);
-            classPool.classNameChanged(oldClassName, this);
-        }
-    }
-
-    public void replaceClassName(String oldname, String newname)
-        throws RuntimeException 
-    {
-        String thisname = getName();
-        if (thisname.equals(oldname))
-            setName(newname);
-        else {
-            super.replaceClassName(oldname, newname);
-            getClassFile2().renameClass(oldname, newname);
-            eraseCache();
-        }
-    }
-
-    public boolean isInterface() {
-        return Modifier.isInterface(getModifiers());
-    }
-
-    public int getModifiers() {
-        int acc = getClassFile2().getAccessFlags();
-        acc = AccessFlag.clear(acc, AccessFlag.SUPER);
-        return AccessFlag.toModifier(acc);
-    }
-
-    public void setModifiers(int mod) {
-        checkModify();
-        int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
-        getClassFile2().setAccessFlags(acc);
-    }
-
-    public boolean subclassOf(CtClass superclass) {
-        if (superclass == null)
-            return false;
-
-        String superName = superclass.getName();
-        CtClass curr = this;
-        try {
-            while (curr != null) {
-                if (curr.getName().equals(superName))
-                    return true;
-
-                curr = curr.getSuperclass();
-            }
-        }
-        catch (Exception ignored) {}
-        return false;
-    }
-
-    public CtClass getSuperclass() throws NotFoundException {
-        String supername = getClassFile2().getSuperclass();
-        if (supername == null)
-            return null;
-        else
-            return classPool.get(supername);
-    }
-
-    public void setSuperclass(CtClass clazz) throws CannotCompileException {
-        checkModify();
-        if (isInterface())
-            addInterface(clazz);
-        else
-            getClassFile2().setSuperclass(clazz.getName());
-    }
-
-    public CtClass[] getInterfaces() throws NotFoundException {
-        String[] ifs = getClassFile2().getInterfaces();
-        int num = ifs.length;
-        CtClass[] ifc = new CtClass[num];
-        for (int i = 0; i < num; ++i)
-            ifc[i] = classPool.get(ifs[i]);
-
-        return ifc;
-    }
-
-    public void setInterfaces(CtClass[] list) {
-        checkModify();
-        String[] ifs;
-        if (list == null)
-            ifs = new String[0];
-        else {
-            int num = list.length;
-            ifs = new String[num];
-            for (int i = 0; i < num; ++i)
-                ifs[i] = list[i].getName();
-        }
-
-        getClassFile2().setInterfaces(ifs);
-    }
-
-    public void addInterface(CtClass anInterface) {
-        checkModify();
-        if (anInterface != null)
-            getClassFile2().addInterface(anInterface.getName());
-    }
-
-    public CtClass getDeclaringClass() throws NotFoundException {
-        ClassFile cf = getClassFile2();
-        InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
-                                                InnerClassesAttribute.tag);
-        if (ica == null)
-            return null;
-
-        String name = getName();
-        int n = ica.tableLength();
-        for (int i = 0; i < n; ++i)
-            if (name.equals(ica.innerClass(i)))
-                return classPool.get(ica.outerClass(i));
-
-        return null;
-    }
-
-    public CtClass makeNestedClass(String name, boolean isStatic) {
-        if (!isStatic)
-            throw new RuntimeException(
-                        "sorry, only nested static class is supported");
-
-        checkModify();
-        CtClass c = classPool.makeNestedClass(getName() + "$" + name);
-        ClassFile cf = getClassFile2();
-        InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
-                                                InnerClassesAttribute.tag);
-        if (ica == null) {
-            ica = new InnerClassesAttribute(cf.getConstPool());
-            cf.addAttribute(ica);
-        }
-
-        ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC);
-        ClassFile cf2 = c.getClassFile2();
-        cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
-        return c;
-    }
-
-    public CtField[] getFields() {
-        ArrayList alist = new ArrayList();
-        getFields(alist, this);
-        return (CtField[])alist.toArray(new CtField[alist.size()]);
-    }
-
-    private static void getFields(ArrayList alist, CtClass cc) {
-        int i, num;
-        if (cc == null)
-            return;
-
-        try {
-            getFields(alist, cc.getSuperclass());
-        }
-        catch (NotFoundException e) {}
-
-        try {
-            CtClass[] ifs = cc.getInterfaces();
-            num = ifs.length;
-            for (i = 0; i < num; ++i)
-                getFields(alist, ifs[i]);
-        }
-        catch (NotFoundException e) {}
-
-        CtField cf = ((CtClassType)cc).getFieldsCache();
-        while (cf != null) {
-            if (Modifier.isPublic(cf.getModifiers()))
-                alist.add(cf);
-
-            cf = cf.next;
-        }
-    }
-
-    public CtField getField(String name) throws NotFoundException {
-        CtField f = getField2(name);
-        if (f == null)
-            throw new NotFoundException("field: " + name + " in " + getName());
-        else
-            return f;
-    }
-
-    CtField getField2(String name) {
-        CtField df = getDeclaredField2(name);
-        if (df != null)
-            return df;
-
-        try {
-            CtClass[] ifs = getInterfaces();
-            int num = ifs.length;
-            for (int i = 0; i < num; ++i) {
-                CtField f = ifs[i].getField2(name);
-                if (f != null)
-                    return f;
-            }
+      return false;
+   }
+
+   public void setName(String name) throws RuntimeException
+   {
+      String oldname = getName();
+      if (name.equals(oldname))
+         return;
+
+      // check this in advance although classNameChanged() below does.
+      classPool.checkNotFrozen(name);
+      ClassFile cf = getClassFile2();
+      super.setName(name);
+      cf.setName(name);
+      eraseCache();
+      classPool.classNameChanged(oldname, this);
+   }
+
+   public void replaceClassName(ClassMap classnames)
+           throws RuntimeException
+   {
+      String oldClassName = getName();
+      String newClassName
+              = (String) classnames.get(Descriptor.toJvmName(oldClassName));
+      if (newClassName != null)
+      {
+         newClassName = Descriptor.toJavaName(newClassName);
+         // check this in advance although classNameChanged() below does.
+         classPool.checkNotFrozen(newClassName);
+      }
+
+      super.replaceClassName(classnames);
+      ClassFile cf = getClassFile2();
+      cf.renameClass(classnames);
+      eraseCache();
+
+      if (newClassName != null)
+      {
+         super.setName(newClassName);
+         classPool.classNameChanged(oldClassName, this);
+      }
+   }
+
+   public void replaceClassName(String oldname, String newname)
+           throws RuntimeException
+   {
+      String thisname = getName();
+      if (thisname.equals(oldname))
+         setName(newname);
+      else
+      {
+         super.replaceClassName(oldname, newname);
+         getClassFile2().renameClass(oldname, newname);
+         eraseCache();
+      }
+   }
+
+   public boolean isInterface()
+   {
+      return Modifier.isInterface(getModifiers());
+   }
+
+   public int getModifiers()
+   {
+      int acc = getClassFile2().getAccessFlags();
+      acc = AccessFlag.clear(acc, AccessFlag.SUPER);
+      return AccessFlag.toModifier(acc);
+   }
+
+   public void setModifiers(int mod)
+   {
+      checkModify();
+      int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
+      getClassFile2().setAccessFlags(acc);
+   }
+
+   public boolean subclassOf(CtClass superclass)
+   {
+      if (superclass == null)
+         return false;
+
+      String superName = superclass.getName();
+      CtClass curr = this;
+      try
+      {
+         while (curr != null)
+         {
+            if (curr.getName().equals(superName))
+               return true;
+
+            curr = curr.getSuperclass();
+         }
+      }
+      catch (Exception ignored)
+      {
+      }
+      return false;
+   }
+
+   public CtClass getSuperclass() throws NotFoundException
+   {
+      String supername = getClassFile2().getSuperclass();
+      if (supername == null)
+         return null;
+      else
+         return classPool.get(supername);
+   }
+
+   public void setSuperclass(CtClass clazz) throws CannotCompileException
+   {
+      checkModify();
+      if (isInterface())
+         addInterface(clazz);
+      else
+         getClassFile2().setSuperclass(clazz.getName());
+   }
+
+   public CtClass[] getInterfaces() throws NotFoundException
+   {
+      String[] ifs = getClassFile2().getInterfaces();
+      int num = ifs.length;
+      CtClass[] ifc = new CtClass[num];
+      for (int i = 0; i < num; ++i)
+         ifc[i] = classPool.get(ifs[i]);
+
+      return ifc;
+   }
+
+   public void setInterfaces(CtClass[] list)
+   {
+      checkModify();
+      String[] ifs;
+      if (list == null)
+         ifs = new String[0];
+      else
+      {
+         int num = list.length;
+         ifs = new String[num];
+         for (int i = 0; i < num; ++i)
+            ifs[i] = list[i].getName();
+      }
+
+      getClassFile2().setInterfaces(ifs);
+   }
+
+   public void addInterface(CtClass anInterface)
+   {
+      checkModify();
+      if (anInterface != null)
+         getClassFile2().addInterface(anInterface.getName());
+   }
+
+   public CtClass getDeclaringClass() throws NotFoundException
+   {
+      ClassFile cf = getClassFile2();
+      InnerClassesAttribute ica = (InnerClassesAttribute) cf.getAttribute(InnerClassesAttribute.tag);
+      if (ica == null)
+         return null;
+
+      String name = getName();
+      int n = ica.tableLength();
+      for (int i = 0; i < n; ++i)
+         if (name.equals(ica.innerClass(i)))
+            return classPool.get(ica.outerClass(i));
+
+      return null;
+   }
+
+   public CtClass makeNestedClass(String name, boolean isStatic)
+   {
+      if (!isStatic)
+         throw new RuntimeException("sorry, only nested static class is supported");
+
+      checkModify();
+      CtClass c = classPool.makeNestedClass(getName() + "$" + name);
+      ClassFile cf = getClassFile2();
+      InnerClassesAttribute ica = (InnerClassesAttribute) cf.getAttribute(InnerClassesAttribute.tag);
+      if (ica == null)
+      {
+         ica = new InnerClassesAttribute(cf.getConstPool());
+         cf.addAttribute(ica);
+      }
+
+      ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC);
+      ClassFile cf2 = c.getClassFile2();
+      cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
+      return c;
+   }
+
+   public CtField[] getFields()
+   {
+      ArrayList alist = new ArrayList();
+      getFields(alist, this);
+      return (CtField[]) alist.toArray(new CtField[alist.size()]);
+   }
+
+   private static void getFields(ArrayList alist, CtClass cc)
+   {
+      int i, num;
+      if (cc == null)
+         return;
+
+      try
+      {
+         getFields(alist, cc.getSuperclass());
+      }
+      catch (NotFoundException e)
+      {
+      }
+
+      try
+      {
+         CtClass[] ifs = cc.getInterfaces();
+         num = ifs.length;
+         for (i = 0; i < num; ++i)
+            getFields(alist, ifs[i]);
+      }
+      catch (NotFoundException e)
+      {
+      }
+
+      CtField cf = ((CtClassType) cc).getFieldsCache();
+      while (cf != null)
+      {
+         if (Modifier.isPublic(cf.getModifiers()))
+            alist.add(cf);
+
+         cf = cf.next;
+      }
+   }
+
+   public CtField getField(String name) throws NotFoundException
+   {
+      CtField f = getField2(name);
+      if (f == null)
+         throw new NotFoundException("field: " + name + " in " + getName());
+      else
+         return f;
+   }
+
+   CtField getField2(String name)
+   {
+      CtField df = getDeclaredField2(name);
+      if (df != null)
+         return df;
+
+      try
+      {
+         CtClass[] ifs = getInterfaces();
+         int num = ifs.length;
+         for (int i = 0; i < num; ++i)
+         {
+            CtField f = ifs[i].getField2(name);
+            if (f != null)
+               return f;
+         }
+
+         CtClass s = getSuperclass();
+         if (s != null)
+            return s.getField2(name);
+      }
+      catch (NotFoundException e)
+      {
+      }
+      return null;
+   }
+
+   public CtField[] getDeclaredFields()
+   {
+      CtField cf = getFieldsCache();
+      int num = CtField.count(cf);
+      CtField[] cfs = new CtField[num];
+      int i = 0;
+      while (cf != null)
+      {
+         cfs[i++] = cf;
+         cf = cf.next;
+      }
+
+      return cfs;
+   }
+
+   protected CtField getFieldsCache()
+   {
+      if (fieldsCache == null)
+      {
+         List list = getClassFile2().getFields();
+         int n = list.size();
+         for (int i = 0; i < n; ++i)
+         {
+            FieldInfo finfo = (FieldInfo) list.get(i);
+            fieldsCache = CtField.append(fieldsCache,
+                    new CtField(finfo, this));
+         }
+      }
+
+      return fieldsCache;
+   }
+
+   public CtField getDeclaredField(String name) throws NotFoundException
+   {
+      CtField f = getDeclaredField2(name);
+      if (f == null)
+         throw new NotFoundException("field: " + name + " in " + getName());
+      else
+         return f;
+   }
+
+   private CtField getDeclaredField2(String name)
+   {
+      CtField cf = getFieldsCache();
+      while (cf != null)
+      {
+         if (cf.getName().equals(name))
+            return cf;
+
+         cf = cf.next;
+      }
+
+      return null;
+   }
+
+   public CtBehavior[] getDeclaredBehaviors()
+   {
+      CtConstructor cc = getConstructorsCache();
+      CtMethod cm = getMethodsCache();
+      int num = CtMethod.count(cm) + CtConstructor.count(cc);
+      CtBehavior[] cb = new CtBehavior[num];
+      int i = 0;
+      while (cc != null)
+      {
+         cb[i++] = cc;
+         cc = cc.next;
+      }
+
+      while (cm != null)
+      {
+         cb[i++] = cm;
+         cm = cm.next;
+      }
+
+      return cb;
+   }
+
+   public CtConstructor[] getConstructors()
+   {
+      CtConstructor[] cons = getDeclaredConstructors();
+      if (cons.length == 0)
+         return cons;
+
+      int n = 0;
+      int i = cons.length;
+      while (--i >= 0)
+         if (Modifier.isPublic(cons[i].getModifiers()))
+            ++n;
+
+      CtConstructor[] result = new CtConstructor[n];
+      n = 0;
+      i = cons.length;
+      while (--i >= 0)
+      {
+         CtConstructor c = cons[i];
+         if (Modifier.isPublic(c.getModifiers()))
+            result[n++] = c;
+      }
+
+      return result;
+   }
+
+   public CtConstructor getConstructor(String desc)
+           throws NotFoundException
+   {
+      CtConstructor cc = getConstructorsCache();
+      while (cc != null)
+      {
+         if (cc.getMethodInfo2().getDescriptor().equals(desc))
+            return cc;
+
+         cc = cc.next;
+      }
+
+      return super.getConstructor(desc);
+   }
+
+   public CtConstructor[] getDeclaredConstructors()
+   {
+      CtConstructor cc = getConstructorsCache();
+      int num = CtConstructor.count(cc);
+      CtConstructor[] ccs = new CtConstructor[num];
+      int i = 0;
+      while (cc != null)
+      {
+         ccs[i++] = cc;
+         cc = cc.next;
+      }
+
+      return ccs;
+   }
+
+   protected CtConstructor getConstructorsCache()
+   {
+      if (constructorsCache == null)
+      {
+         List list = getClassFile2().getMethods();
+         int n = list.size();
+         for (int i = 0; i < n; ++i)
+         {
+            MethodInfo minfo = (MethodInfo) list.get(i);
+            if (minfo.isConstructor())
+               constructorsCache
+                       = CtConstructor.append(constructorsCache,
+                               new CtConstructor(minfo, this));
+         }
+      }
+
+      return constructorsCache;
+   }
+
+   public CtConstructor getClassInitializer()
+   {
+      if (classInitializerCache == null)
+      {
+         MethodInfo minfo = getClassFile2().getStaticInitializer();
+         if (minfo != null)
+            classInitializerCache = new CtConstructor(minfo, this);
+      }
+
+      return classInitializerCache;
+   }
+
+   public CtMethod[] getMethods()
+   {
+      HashMap h = new HashMap();
+      getMethods0(h, this);
+      return (CtMethod[]) h.values().toArray(new CtMethod[0]);
+   }
+
+   private static void getMethods0(HashMap h, CtClass cc)
+   {
+      try
+      {
+         CtClass[] ifs = cc.getInterfaces();
+         int size = ifs.length;
+         for (int i = 0; i < size; ++i)
+            getMethods0(h, ifs[i]);
+      }
+      catch (NotFoundException e)
+      {
+      }
+
+      try
+      {
+         CtClass s = cc.getSuperclass();
+         if (s != null)
+            getMethods0(h, s);
+      }
+      catch (NotFoundException e)
+      {
+      }
+
+      if (cc instanceof CtClassType)
+      {
+         CtMethod cm = ((CtClassType) cc).getMethodsCache();
+         while (cm != null)
+         {
+            if (Modifier.isPublic(cm.getModifiers()))
+               h.put(cm.getStringRep(), cm);
 
-            CtClass s = getSuperclass();
-            if (s != null)
-                return s.getField2(name);
-        }
-        catch (NotFoundException e) {}
-        return null;
-    }
-
-    public CtField[] getDeclaredFields() {
-        CtField cf = getFieldsCache();
-        int num = CtField.count(cf);
-        CtField[] cfs = new CtField[num];
-        int i = 0;
-        while (cf != null) {
-            cfs[i++] = cf;
-            cf = cf.next;
-        }
-
-        return cfs;
-    }
-
-    protected CtField getFieldsCache() {
-        if (fieldsCache == null) {
-            List list = getClassFile2().getFields();
-            int n = list.size();
-            for (int i = 0; i < n; ++i) {
-                FieldInfo finfo = (FieldInfo)list.get(i);
-                fieldsCache = CtField.append(fieldsCache,
-                                             new CtField(finfo, this));
-            }
-        }
-
-        return fieldsCache;
-    }
-
-    public CtField getDeclaredField(String name) throws NotFoundException {
-        CtField f = getDeclaredField2(name);
-        if (f == null)
-            throw new NotFoundException("field: " + name + " in " + getName());
-        else
-            return f;
-    }
-
-    private CtField getDeclaredField2(String name) {
-        CtField cf = getFieldsCache();
-        while (cf != null) {
-            if (cf.getName().equals(name))
-                return cf;
-
-            cf = cf.next;
-        }
-
-        return null;
-    }
-
-    public CtBehavior[] getDeclaredBehaviors() {
-        CtConstructor cc = getConstructorsCache();
-        CtMethod cm = getMethodsCache();
-        int num = CtMethod.count(cm) + CtConstructor.count(cc);
-        CtBehavior[] cb = new CtBehavior[num];
-        int i = 0;
-        while (cc != null) {
-            cb[i++] = cc;
-            cc = cc.next;
-        }
-
-        while (cm != null) {
-            cb[i++] = cm;
             cm = cm.next;
-        }
-        
-        return cb;
-    }
-
-    public CtConstructor[] getConstructors() {
-        CtConstructor[] cons = getDeclaredConstructors();
-        if (cons.length == 0)
-            return cons;
-
-        int n = 0;
-        int i = cons.length;
-        while (--i >= 0)
-            if (Modifier.isPublic(cons[i].getModifiers()))
-                ++n;
-
-        CtConstructor[] result = new CtConstructor[n];
-        n = 0;
-        i = cons.length;
-        while (--i >= 0) {
-            CtConstructor c = cons[i];
-            if (Modifier.isPublic(c.getModifiers()))
-                result[n++] = c;
-        }
-
-        return result;
-    }
-
-    public CtConstructor getConstructor(String desc)
-        throws NotFoundException
-    {
-        CtConstructor cc = getConstructorsCache();
-        while (cc != null) {
-            if (cc.getMethodInfo2().getDescriptor().equals(desc))
-                return cc;
-
-            cc = cc.next;
-        }
-
-        return super.getConstructor(desc);
-    }
-
-    public CtConstructor[] getDeclaredConstructors() {
-        CtConstructor cc = getConstructorsCache();
-        int num = CtConstructor.count(cc);
-        CtConstructor[] ccs = new CtConstructor[num];
-        int i = 0;
-        while (cc != null) {
-            ccs[i++] = cc;
-            cc = cc.next;
-        }
-        
-        return ccs;
-    }
-
-    protected CtConstructor getConstructorsCache() {
-        if (constructorsCache == null) {
-            List list = getClassFile2().getMethods();
-            int n = list.size();
-            for (int i = 0; i < n; ++i) {
-                MethodInfo minfo = (MethodInfo)list.get(i);
-                if (minfo.isConstructor())
-                    constructorsCache
-                        = CtConstructor.append(constructorsCache,
-                                            new CtConstructor(minfo, this));
-            }
-        }
-
-        return constructorsCache;
-    }
-
-    public CtConstructor getClassInitializer() {
-        if (classInitializerCache == null) {
-            MethodInfo minfo = getClassFile2().getStaticInitializer();
-            if (minfo != null)
-                classInitializerCache = new CtConstructor(minfo, this);
-        }
-
-        return classInitializerCache;
-    }
-
-    public CtMethod[] getMethods() {
-        HashMap h = new HashMap();
-        getMethods0(h, this);
-        return (CtMethod[])h.values().toArray(new CtMethod[0]);
-    }
-
-    private static void getMethods0(HashMap h, CtClass cc) {
-        try {
-            CtClass[] ifs = cc.getInterfaces();
-            int size = ifs.length;
-            for (int i = 0; i < size; ++i)
-                getMethods0(h, ifs[i]);
-        }
-        catch (NotFoundException e) {}
-
-        try {
-            CtClass s = cc.getSuperclass();
-            if (s != null)
-                getMethods0(h, s);
-        }
-        catch (NotFoundException e) {}
-
-        if (cc instanceof CtClassType) {
-            CtMethod cm = ((CtClassType)cc).getMethodsCache();
-            while (cm != null) {
-                if (Modifier.isPublic(cm.getModifiers()))
-                    h.put(cm.getStringRep(), cm);
-
-                cm = cm.next;
-            }
-        }
-    }
-
-    public CtMethod getMethod(String name, String desc)
-        throws NotFoundException
-    {
-        CtMethod m = getMethod0(this, name, desc);
-        if (m != null)
-            return m;
-        else
-            throw new NotFoundException(name + "(..) is not found in "
-                                        + getName());
-    }
-
-    private static CtMethod getMethod0(CtClass cc,
-                                       String name, String desc) {
-        if (cc instanceof CtClassType) {
-            CtMethod cm = ((CtClassType)cc).getMethodsCache();
-            while (cm != null) {
-                if (cm.getName().equals(name)
+         }
+      }
+   }
+
+   public CtMethod getMethod(String name, String desc)
+           throws NotFoundException
+   {
+      CtMethod m = getMethod0(this, name, desc);
+      if (m != null)
+         return m;
+      else
+         throw new NotFoundException(name + "(..) is not found in "
+                 + getName());
+   }
+
+   private static CtMethod getMethod0(CtClass cc,
+                                      String name, String desc)
+   {
+      if (cc instanceof CtClassType)
+      {
+         CtMethod cm = ((CtClassType) cc).getMethodsCache();
+         while (cm != null)
+         {
+            if (cm.getName().equals(name)
                     && cm.getMethodInfo2().getDescriptor().equals(desc))
-                    return cm;
+               return cm;
 
-                cm = cm.next;
-            }
-        }
-
-        try {
-            CtClass s = cc.getSuperclass();
-            if (s != null) {
-                CtMethod m = getMethod0(s, name, desc);
-                if (m != null)
-                    return m;
-            }
-        }
-        catch (NotFoundException e) {}
-
-        try {
-            CtClass[] ifs = cc.getInterfaces();
-            int size = ifs.length;
-            for (int i = 0; i < size; ++i) {
-                CtMethod m = getMethod0(ifs[i], name, desc);
-                if (m != null)
-                    return m;
-            }
-        }
-        catch (NotFoundException e) {}
-        return null;
-    }
-
-    public CtMethod[] getDeclaredMethods() {
-        CtMethod cm = getMethodsCache();
-        int num = CtMethod.count(cm);
-        CtMethod[] cms = new CtMethod[num];
-        int i = 0;
-        while (cm != null) {
-            cms[i++] = cm;
             cm = cm.next;
-        }
-        
-        return cms;
-    }
-
-    public CtMethod getDeclaredMethod(String name) throws NotFoundException {
-        CtMethod m = getMethodsCache();
-        while (m != null) {
-            if (m.getName().equals(name))
-                return m;
-
-            m = m.next;
-        }
-
-        throw new NotFoundException(name + "(..) is not found in "
-                                    + getName());
-    }
-
-    public CtMethod getDeclaredMethod(String name, CtClass[] params)
-        throws NotFoundException
-    {
-        String desc = Descriptor.ofParameters(params);
-        CtMethod m = getMethodsCache();
-        while (m != null) {
-            if (m.getName().equals(name)
-                && m.getMethodInfo2().getDescriptor().startsWith(desc))
-                return m;
-
-            m = m.next;
-        }
-
-        throw new NotFoundException(name + "(..) is not found in "
-                                    + getName());
-    }
-
-    protected CtMethod getMethodsCache() {
-        if (methodsCache == null) {
-            List list = getClassFile2().getMethods();
-            int n = list.size();
-            for (int i = 0; i < n; ++i) {
-                MethodInfo minfo = (MethodInfo)list.get(i);
-                if (minfo.isMethod())
-                    methodsCache = CtMethod.append(methodsCache,
-                                                new CtMethod(minfo, this));
-            }
-        }
-
-        return methodsCache;
-    }
-
-    public void addField(CtField f, String init)
-        throws CannotCompileException
-    {
-        addField(f, CtField.Initializer.byExpr(init));
-    }
-
-    public void addField(CtField f, CtField.Initializer init)
-        throws CannotCompileException
-    {
-        checkModify();
-        if (f.getDeclaringClass() != this)
-            throw new CannotCompileException("cannot add");
-
-        if (init == null)
-            init = f.getInit();
-
-        getFieldsCache();
-        fieldsCache = CtField.append(fieldsCache, f);
-        getClassFile2().addField(f.getFieldInfo2());
-
-        if (init != null) {
-            FieldInitLink fil = new FieldInitLink(f, init);
-            FieldInitLink link = fieldInitializers;
-            if (link == null)
-                fieldInitializers = fil;
-            else {
-                while (link.next != null)
-                    link = link.next;
-
-                link.next = fil;
-            }
-        }
-    }
-
-    public CtConstructor makeClassInitializer()
-        throws CannotCompileException
-    {
-        CtConstructor clinit = getClassInitializer();
-        if (clinit != null)
-            return clinit;
-
-        checkModify();
-        ClassFile cf = getClassFile2();
-        Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
-        modifyClassConstructor(cf, code, 0, 0);
-        return getClassInitializer();
-    }
-
-    public void addConstructor(CtConstructor c)
-        throws CannotCompileException
-    {
-        checkModify();
-        if (c.getDeclaringClass() != this)
-            throw new CannotCompileException("cannot add");
-
-        getConstructorsCache();
-        constructorsCache = CtConstructor.append(constructorsCache, c);
-        getClassFile2().addMethod(c.getMethodInfo2());
-    }
-
-    public void addMethod(CtMethod m) throws CannotCompileException {
-        checkModify();
-        if (m.getDeclaringClass() != this)
-            throw new CannotCompileException("cannot add");
-
-        getMethodsCache();
-        methodsCache = CtMethod.append(methodsCache, m);
-        getClassFile2().addMethod(m.getMethodInfo2());
-        if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
-            setModifiers(getModifiers() | Modifier.ABSTRACT);
-    }
-
-    public byte[] getAttribute(String name) {
-        AttributeInfo ai = getClassFile2().getAttribute(name);
-        if (ai == null)
-            return null;
-        else
-            return ai.get();
-    }
-
-    public void setAttribute(String name, byte[] data) {
-        checkModify();
-        ClassFile cf = getClassFile2();
-        cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
-    }
-
-    public void instrument(CodeConverter converter)
-        throws CannotCompileException
-    {
-        checkModify();
-        ClassFile cf = getClassFile2();
-        ConstPool cp = cf.getConstPool();
-        List list = cf.getMethods();
-        int n = list.size();
-        for (int i = 0; i < n; ++i) {
-            MethodInfo minfo = (MethodInfo)list.get(i);
-            converter.doit(this, minfo, cp);
-        }
-    }
-
-    public void instrument(ExprEditor editor)
-        throws CannotCompileException
-    {
-        checkModify();
-        ClassFile cf = getClassFile2();
-        List list = cf.getMethods();
-        int n = list.size();
-        for (int i = 0; i < n; ++i) {
-            MethodInfo minfo = (MethodInfo)list.get(i);
-            editor.doit(this, minfo);
-        }
-    }
-
-    public void toBytecode(DataOutputStream out)
-        throws CannotCompileException, IOException
-    {
-        try {
-            if (isModified()) {
-                checkPruned("toBytecode");
-                ClassFile cf = getClassFile2();
-                modifyClassConstructor(cf);
-                modifyConstructors(cf);
-                cf.write(out);
-                out.flush();
-                fieldInitializers = null;
-                if (doPruning) {
-                    // to save memory
-                    cf.prune();
-                    wasPruned = true;
-                }
-            }
-            else {
-                classPool.writeClassfile(getName(), out);
-                // to save memory
-                eraseCache();
-                classfile = null;
-            }
+         }
+      }
+
+      try
+      {
+         CtClass s = cc.getSuperclass();
+         if (s != null)
+         {
+            CtMethod m = getMethod0(s, name, desc);
+            if (m != null)
+               return m;
+         }
+      }
+      catch (NotFoundException e)
+      {
+      }
+
+      try
+      {
+         CtClass[] ifs = cc.getInterfaces();
+         int size = ifs.length;
+         for (int i = 0; i < size; ++i)
+         {
+            CtMethod m = getMethod0(ifs[i], name, desc);
+            if (m != null)
+               return m;
+         }
+      }
+      catch (NotFoundException e)
+      {
+      }
+      return null;
+   }
+
+   public CtMethod[] getDeclaredMethods()
+   {
+      CtMethod cm = getMethodsCache();
+      int num = CtMethod.count(cm);
+      CtMethod[] cms = new CtMethod[num];
+      int i = 0;
+      while (cm != null)
+      {
+         cms[i++] = cm;
+         cm = cm.next;
+      }
+
+      return cms;
+   }
+
+   public CtMethod getDeclaredMethod(String name) throws NotFoundException
+   {
+      CtMethod m = getMethodsCache();
+      while (m != null)
+      {
+         if (m.getName().equals(name))
+            return m;
 
-            wasFrozen = true;
-        }
-        catch (NotFoundException e) {
-            throw new CannotCompileException(e);
-        }
-        catch (IOException e) {
-            throw new CannotCompileException(e);
-        }
-    }
-
-    private void checkPruned(String method) {
-        if (wasPruned)
-            throw new RuntimeException(method + "(): " + getName()
-                                       + " was pruned.");
-    }
-
-    public void stopPruning(boolean stop) {
-        doPruning = !stop;
-    }
-
-    private void modifyClassConstructor(ClassFile cf)
-        throws CannotCompileException, NotFoundException
-    {
-        if (fieldInitializers == null)
-            return;
-
-        Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
-        Javac jv = new Javac(code, this);
-        int stacksize = 0;
-        boolean doInit = false;
-        for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
-            CtField f = fi.field;
-            if (Modifier.isStatic(f.getModifiers())) {
-                doInit = true;
-                int s = fi.init.compileIfStatic(f.getType(), f.getName(),
-                                                code, jv);
-                if (stacksize < s)
-                    stacksize = s;
-            }
-        }
-
-        if (doInit)    // need an initializer for static fileds.
-            modifyClassConstructor(cf, code, stacksize, 0);
-    }
-
-    private void modifyClassConstructor(ClassFile cf, Bytecode code,
-                                        int stacksize, int localsize)
-        throws CannotCompileException
-    {
-        MethodInfo m = cf.getStaticInitializer();
-        if (m == null) {
-            code.add(Bytecode.RETURN);
-            code.setMaxStack(stacksize);
-            code.setMaxLocals(localsize);
-            m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
-            m.setAccessFlags(AccessFlag.STATIC);
-            m.setCodeAttribute(code.toCodeAttribute());
-            cf.addMethod(m);
-        }
-        else {
-            CodeAttribute codeAttr = m.getCodeAttribute();
-            if (codeAttr == null)
-                throw new CannotCompileException("empty <clinit>");
-
-            try {
-                CodeIterator it = codeAttr.iterator();
-                int pos = it.insertEx(code.get());
-                it.insert(code.getExceptionTable(), pos);
-                int maxstack = codeAttr.getMaxStack();
-                if (maxstack < stacksize)
-                    codeAttr.setMaxStack(stacksize);
-
-                int maxlocals = codeAttr.getMaxLocals();
-                if (maxlocals < localsize)
-                    codeAttr.setMaxLocals(localsize);
-            }
-            catch (BadBytecode e) {
-                throw new CannotCompileException(e);
-            }
-        }
-    }
-
-    private void modifyConstructors(ClassFile cf)
-        throws CannotCompileException, NotFoundException
-    {
-        if (fieldInitializers == null)
-            return;
-
-        ConstPool cp = cf.getConstPool();
-        List list = cf.getMethods();
-        int n = list.size();
-        for (int i = 0; i < n; ++i) {
-            MethodInfo minfo = (MethodInfo)list.get(i);
-            if (minfo.isConstructor()) {
-                CodeAttribute codeAttr = minfo.getCodeAttribute();
-                if (codeAttr != null)
-                    try {
-                        Bytecode init = new Bytecode(cp, 0,
-                                             codeAttr.getMaxLocals());
-                        CtClass[] params
-                            = Descriptor.getParameterTypes(
-                                                minfo.getDescriptor(),
-                                                classPool);
-                        int stacksize = makeFieldInitializer(init, params);
-                        insertAuxInitializer(codeAttr, init, stacksize);
-                    }
-                    catch (BadBytecode e) {
-                        throw new CannotCompileException(e);
-                    }
+         m = m.next;
+      }
+
+      throw new NotFoundException(name + "(..) is not found in "
+              + getName());
+   }
+
+   public CtMethod getDeclaredMethod(String name, CtClass[] params)
+           throws NotFoundException
+   {
+      String desc = Descriptor.ofParameters(params);
+      CtMethod m = getMethodsCache();
+      while (m != null)
+      {
+         if (m.getName().equals(name)
+                 && m.getMethodInfo2().getDescriptor().startsWith(desc))
+            return m;
+
+         m = m.next;
+      }
+
+      throw new NotFoundException(name + "(..) is not found in "
+              + getName());
+   }
+
+   protected CtMethod getMethodsCache()
+   {
+      if (methodsCache == null)
+      {
+         List list = getClassFile2().getMethods();
+         int n = list.size();
+         for (int i = 0; i < n; ++i)
+         {
+            MethodInfo minfo = (MethodInfo) list.get(i);
+            if (minfo.isMethod())
+               methodsCache = CtMethod.append(methodsCache,
+                       new CtMethod(minfo, this));
+         }
+      }
+
+      return methodsCache;
+   }
+
+   public void addField(CtField f, String init)
+           throws CannotCompileException
+   {
+      addField(f, CtField.Initializer.byExpr(init));
+   }
+
+   public void addField(CtField f, CtField.Initializer init)
+           throws CannotCompileException
+   {
+      checkModify();
+      if (f.getDeclaringClass() != this)
+         throw new CannotCompileException("cannot add");
+
+      if (init == null)
+         init = f.getInit();
+
+      getFieldsCache();
+      fieldsCache = CtField.append(fieldsCache, f);
+      getClassFile2().addField(f.getFieldInfo2());
+
+      if (init != null)
+      {
+         FieldInitLink fil = new FieldInitLink(f, init);
+         FieldInitLink link = fieldInitializers;
+         if (link == null)
+            fieldInitializers = fil;
+         else
+         {
+            while (link.next != null)
+               link = link.next;
+
+            link.next = fil;
+         }
+      }
+   }
+
+   public CtConstructor makeClassInitializer()
+           throws CannotCompileException
+   {
+      CtConstructor clinit = getClassInitializer();
+      if (clinit != null)
+         return clinit;
+
+      checkModify();
+      ClassFile cf = getClassFile2();
+      Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
+      modifyClassConstructor(cf, code, 0, 0);
+      return getClassInitializer();
+   }
+
+   public void addConstructor(CtConstructor c)
+           throws CannotCompileException
+   {
+      checkModify();
+      if (c.getDeclaringClass() != this)
+         throw new CannotCompileException("cannot add");
+
+      getConstructorsCache();
+      constructorsCache = CtConstructor.append(constructorsCache, c);
+      getClassFile2().addMethod(c.getMethodInfo2());
+   }
+
+   public void addMethod(CtMethod m) throws CannotCompileException
+   {
+      checkModify();
+      if (m.getDeclaringClass() != this)
+         throw new CannotCompileException("cannot add");
+
+      getMethodsCache();
+      methodsCache = CtMethod.append(methodsCache, m);
+      getClassFile2().addMethod(m.getMethodInfo2());
+      if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
+         setModifiers(getModifiers() | Modifier.ABSTRACT);
+   }
+
+   public byte[] getAttribute(String name)
+   {
+      AttributeInfo ai = getClassFile2().getAttribute(name);
+      if (ai == null)
+         return null;
+      else
+         return ai.get();
+   }
+
+   public void setAttribute(String name, byte[] data)
+   {
+      checkModify();
+      ClassFile cf = getClassFile2();
+      cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
+   }
+
+   public void instrument(CodeConverter converter)
+           throws CannotCompileException
+   {
+      checkModify();
+      ClassFile cf = getClassFile2();
+      ConstPool cp = cf.getConstPool();
+      List list = cf.getMethods();
+      int n = list.size();
+      for (int i = 0; i < n; ++i)
+      {
+         MethodInfo minfo = (MethodInfo) list.get(i);
+         converter.doit(this, minfo, cp);
+      }
+   }
+
+   public void instrument(ExprEditor editor)
+           throws CannotCompileException
+   {
+      checkModify();
+      ClassFile cf = getClassFile2();
+      List list = cf.getMethods();
+      int n = list.size();
+      for (int i = 0; i < n; ++i)
+      {
+         MethodInfo minfo = (MethodInfo) list.get(i);
+         editor.doit(this, minfo);
+      }
+   }
+
+   public void toBytecode(DataOutputStream out)
+           throws CannotCompileException, IOException
+   {
+      try
+      {
+         if (isModified())
+         {
+            checkPruned("toBytecode");
+            ClassFile cf = getClassFile2();
+            modifyClassConstructor(cf);
+            modifyConstructors(cf);
+            cf.write(out);
+            out.flush();
+            fieldInitializers = null;
+            if (doPruning)
+            {
+               // to save memory
+               cf.prune();
+               wasPruned = true;
             }
-        }
-    }
-
-    private static void insertAuxInitializer(CodeAttribute codeAttr,
-                                             Bytecode initializer,
-                                             int stacksize)
-        throws BadBytecode
-    {
-        CodeIterator it = codeAttr.iterator();
-        int index = it.skipSuperConstructor();
-        if (index < 0) {
-            index = it.skipThisConstructor();
-            if (index >= 0)
-                return;         // this() is called.
-
-            // Neither this() or super() is called.
-        }
-
-        int pos = it.insertEx(initializer.get());
-        it.insert(initializer.getExceptionTable(), pos);
-        int maxstack = codeAttr.getMaxStack();
-        if (maxstack < stacksize)
-            codeAttr.setMaxStack(stacksize);
-    }
-
-    private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
-        throws CannotCompileException, NotFoundException
-    {
-        int stacksize = 0;
-        Javac jv = new Javac(code, this);
-        try {
-            jv.recordParams(parameters, false);
-        }
-        catch (CompileError e) {
+         }
+         else
+         {
+            classPool.writeClassfile(getName(), out);
+            // to save memory
+            eraseCache();
+            classfile = null;
+         }
+
+         wasFrozen = true;
+      }
+      catch (NotFoundException e)
+      {
+         throw new CannotCompileException(e);
+      }
+      catch (IOException e)
+      {
+         throw new CannotCompileException(e);
+      }
+   }
+
+   private void checkPruned(String method)
+   {
+      if (wasPruned)
+         throw new RuntimeException(method + "(): " + getName()
+                 + " was pruned.");
+   }
+
+   public void stopPruning(boolean stop)
+   {
+      doPruning = !stop;
+   }
+
+   private void modifyClassConstructor(ClassFile cf)
+           throws CannotCompileException, NotFoundException
+   {
+      if (fieldInitializers == null)
+         return;
+
+      Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
+      Javac jv = new Javac(code, this);
+      int stacksize = 0;
+      boolean doInit = false;
+      for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next)
+      {
+         CtField f = fi.field;
+         if (Modifier.isStatic(f.getModifiers()))
+         {
+            doInit = true;
+            int s = fi.init.compileIfStatic(f.getType(), f.getName(),
+                    code, jv);
+            if (stacksize < s)
+               stacksize = s;
+         }
+      }
+
+      if (doInit)    // need an initializer for static fileds.
+         modifyClassConstructor(cf, code, stacksize, 0);
+   }
+
+   private void modifyClassConstructor(ClassFile cf, Bytecode code,
+                                       int stacksize, int localsize)
+           throws CannotCompileException
+   {
+      MethodInfo m = cf.getStaticInitializer();
+      if (m == null)
+      {
+         code.add(Bytecode.RETURN);
+         code.setMaxStack(stacksize);
+         code.setMaxLocals(localsize);
+         m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
+         m.setAccessFlags(AccessFlag.STATIC);
+         m.setCodeAttribute(code.toCodeAttribute());
+         cf.addMethod(m);
+      }
+      else
+      {
+         CodeAttribute codeAttr = m.getCodeAttribute();
+         if (codeAttr == null)
+            throw new CannotCompileException("empty <clinit>");
+
+         try
+         {
+            CodeIterator it = codeAttr.iterator();
+            int pos = it.insertEx(code.get());
+            it.insert(code.getExceptionTable(), pos);
+            int maxstack = codeAttr.getMaxStack();
+            if (maxstack < stacksize)
+               codeAttr.setMaxStack(stacksize);
+
+            int maxlocals = codeAttr.getMaxLocals();
+            if (maxlocals < localsize)
+               codeAttr.setMaxLocals(localsize);
+         }
+         catch (BadBytecode e)
+         {
             throw new CannotCompileException(e);
-        }
-
-        for (FieldInitLink fi = fieldInitializers; fi !=  null; fi = fi.next) {
-            CtField f = fi.field;
-            if (!Modifier.isStatic(f.getModifiers())) {
-                int s = fi.init.compile(f.getType(), f.getName(), code,
-                                        parameters, jv);
-                if (stacksize < s)
-                    stacksize = s;
-            }
-        }
-
-        return stacksize;
-    }
-
-    // Methods used by CtNewWrappedMethod
-
-    Hashtable getHiddenMethods() {
-        if (hiddenMethods == null)
-            hiddenMethods = new Hashtable();
-
-        return hiddenMethods;
-    }
-
-    int getUniqueNumber() { return uniqueNumberSeed++; }
+         }
+      }
+   }
+
+   private void modifyConstructors(ClassFile cf)
+           throws CannotCompileException, NotFoundException
+   {
+      if (fieldInitializers == null)
+         return;
+
+      ConstPool cp = cf.getConstPool();
+      List list = cf.getMethods();
+      int n = list.size();
+      for (int i = 0; i < n; ++i)
+      {
+         MethodInfo minfo = (MethodInfo) list.get(i);
+         if (minfo.isConstructor())
+         {
+            CodeAttribute codeAttr = minfo.getCodeAttribute();
+            if (codeAttr != null)
+               try
+               {
+                  Bytecode init = new Bytecode(cp, 0,
+                          codeAttr.getMaxLocals());
+                  CtClass[] params
+                          = Descriptor.getParameterTypes(minfo.getDescriptor(),
+                                  classPool);
+                  int stacksize = makeFieldInitializer(init, params);
+                  insertAuxInitializer(codeAttr, init, stacksize);
+               }
+               catch (BadBytecode e)
+               {
+                  throw new CannotCompileException(e);
+               }
+         }
+      }
+   }
+
+   private static void insertAuxInitializer(CodeAttribute codeAttr,
+                                            Bytecode initializer,
+                                            int stacksize)
+           throws BadBytecode
+   {
+      CodeIterator it = codeAttr.iterator();
+      int index = it.skipSuperConstructor();
+      if (index < 0)
+      {
+         index = it.skipThisConstructor();
+         if (index >= 0)
+            return;         // this() is called.
+
+         // Neither this() or super() is called.
+      }
+
+      int pos = it.insertEx(initializer.get());
+      it.insert(initializer.getExceptionTable(), pos);
+      int maxstack = codeAttr.getMaxStack();
+      if (maxstack < stacksize)
+         codeAttr.setMaxStack(stacksize);
+   }
+
+   private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
+           throws CannotCompileException, NotFoundException
+   {
+      int stacksize = 0;
+      Javac jv = new Javac(code, this);
+      try
+      {
+         jv.recordParams(parameters, false);
+      }
+      catch (CompileError e)
+      {
+         throw new CannotCompileException(e);
+      }
+
+      for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next)
+      {
+         CtField f = fi.field;
+         if (!Modifier.isStatic(f.getModifiers()))
+         {
+            int s = fi.init.compile(f.getType(), f.getName(), code,
+                    parameters, jv);
+            if (stacksize < s)
+               stacksize = s;
+         }
+      }
+
+      return stacksize;
+   }
+
+   // Methods used by CtNewWrappedMethod
+
+   Hashtable getHiddenMethods()
+   {
+      if (hiddenMethods == null)
+         hiddenMethods = new Hashtable();
+
+      return hiddenMethods;
+   }
+
+   int getUniqueNumber()
+   {
+      return uniqueNumberSeed++;
+   }
 }
 
-class FieldInitLink {
-    FieldInitLink next;
-    CtField field;
-    CtField.Initializer init;
-
-    FieldInitLink(CtField f, CtField.Initializer i) {
-        next = null;
-        field = f;
-        init = i;
-    }
+class FieldInitLink
+{
+   FieldInitLink next;
+   CtField field;
+   CtField.Initializer init;
+
+   FieldInitLink(CtField f, CtField.Initializer i)
+   {
+      next = null;
+      field = f;
+      init = i;
+   }
 }
index a6dfe87a917f6c959ac24d769789dae9031d26ec..2483c01b895072a4b396b99e6bb085969ae375d9 100644 (file)
 
 package javassist.bytecode;
 
-import java.util.Map;
-import java.io.IOException;
-import java.io.DataInputStream;
-import java.io.ByteArrayOutputStream;
+import javassist.bytecode.annotation.Annotation;
+import javassist.bytecode.annotation.AnnotationMemberValue;
+import javassist.bytecode.annotation.AnnotationsWriter;
+import javassist.bytecode.annotation.ArrayMemberValue;
+import javassist.bytecode.annotation.BooleanMemberValue;
+import javassist.bytecode.annotation.ByteMemberValue;
+import javassist.bytecode.annotation.CharMemberValue;
+import javassist.bytecode.annotation.ClassMemberValue;
+import javassist.bytecode.annotation.DoubleMemberValue;
+import javassist.bytecode.annotation.EnumMemberValue;
+import javassist.bytecode.annotation.FloatMemberValue;
+import javassist.bytecode.annotation.IntegerMemberValue;
+import javassist.bytecode.annotation.LongMemberValue;
+import javassist.bytecode.annotation.MemberValue;
+import javassist.bytecode.annotation.ShortMemberValue;
+import javassist.bytecode.annotation.StringMemberValue;
 
-import javassist.bytecode.annotation.*;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A class representing
  * <code>RuntimeVisibleAnnotations_attribute</code> and
  * <code>RuntimeInvisibleAnnotations_attribute</code>.
- *
+ * <p/>
  * <p>To obtain an AnnotationAttribute object, invoke
  * <code>getAttribute(AnnotationsAttribute.invisibleTag)</code>
  * in <code>ClassFile</code>, <code>MethodInfo</code>,
  * or <code>FieldInfo</code>.  The obtained attribute is a
- * runtime invisible annotations attribute.  
+ * runtime invisible annotations attribute.
  * If the parameter is
  * <code>AnnotationAttribute.visibleTag</code>, then the obtained
  * attribute is a runtime visible one.
- *
+ * <p/>
  * <p>If you want to record a new AnnotationAttribute object, execute the
  * following snippet:
- *
+ * <p/>
  * <ul><pre>
  * ClassFile cf = ... ;
  * ConstPool cp = cf.getConstPool();
@@ -50,471 +66,571 @@ import javassist.bytecode.annotation.*;
  * cf.addAttribute(attr);
  * </pre></ul>
  */
-public class AnnotationsAttribute extends AttributeInfo {
-    /**
-     * The name of the <code>RuntimeVisibleAnnotations</code> attribute.
-     */
-    public static final String visibleTag = "RuntimeVisibleAnnotations";
-
-    /**
-     * The name of the <code>RuntimeInvisibleAnnotations</code> attribute.
-     */
-    public static final String invisibleTag = "RuntimeInvisibleAnnotations";
-
-    /**
-     * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>.
-     *
-     * @param cp            constant pool
-     * @param attrname      attribute name (<code>visibleTag</code> or
-     *                      <code>invisibleTag</code>).
-     * @param info          the contents of this attribute.  It does not
-     *                      include <code>attribute_name_index</code> or
-     *                      <code>attribute_length</code>.
-     */
-    public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) {
-        super(cp, attrname, info);
-    }
-
-    /**
-     * Constructs an empty
-     * <code>Runtime(In)VisisbleAnnotations_attribute</code>.
-     * A new annotation can be later added to the created attribute
-     * by <code>setAnnotations()</code>.
-     *
-     * @param cp            constant pool
-     * @param attrname      attribute name (<code>visibleTag</code> or
-     *                      <code>invisibleTag</code>).
-     * @see #setAnnotations(Annotation[])
-     */
-    public AnnotationsAttribute(ConstPool cp, String attrname) {
-        this(cp, attrname, new byte[] { 0, 0 });
-    }
-
-    /**
-     * @param n     the attribute name.
-     */
-    AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
-        throws IOException
-    {
-        super(cp, n, in);
-    }
-
-    /**
-     * Returns <code>num_annotations</code>. 
-     */
-    public int numAnnotations() {
-        return ByteArray.readU16bit(info, 0);
-    }
-
-    /**
-     * Copies this attribute and returns a new copy.
-     */
-    public AttributeInfo copy(ConstPool newCp, Map classnames) {
-        Copier copier = new Copier(info, constPool, newCp, classnames);
-        try {
-            copier.annotationArray();
-            return new AnnotationsAttribute(newCp, getName(), copier.close());
-        }
-        catch (Exception e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Parses the annotations and returns a data structure representing
-     * that parsed annotations.  Note that changes of the node values of the
-     * returned tree are not reflected on the annotations represented by
-     * this object unless the tree is copied back to this object by
-     * <code>setAnnotations()</code>.
-     *
-     * @see #setAnnotations(Annotation[])
-     */
-    public Annotation[] getAnnotations() {
-        try {
-            return new Parser(info, constPool).parseAnnotations();
-        }
-        catch (Exception e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Changes the annotations represented by this object according to
-     * the given array of <code>Annotation</code> objects.
-     *
-     * @param annotations           the data structure representing the
-     *                              new annotations. 
-     */
-    public void setAnnotations(Annotation[] annotations) {
-        ByteArrayOutputStream output = new ByteArrayOutputStream();
-        AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
-        try {
-            int n = annotations.length;
-            writer.numAnnotations(n);
-            for (int i = 0; i < n; ++i)
-                annotations[i].write(writer);
-
-            writer.close();
-        }
-        catch (IOException e) {
-            throw new RuntimeException(e);      // should never reach here.
-        }
-
-        set(output.toByteArray());
-    }
-
-    /**
-     * Changes the annotations.  A call to this method is equivalent to:
-     * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul>
-     *
-     * @param annotation    the data structure representing
-     *                      the new annotation.
-     */
-    public void setAnnotation(Annotation annotation) {
-        setAnnotations(new Annotation[] { annotation });
-    }
-
-    /**
-     * Returns a string representation of this object.
-     */
-    public String toString() {
-        Annotation[] a = getAnnotations();
-        StringBuffer sbuf = new StringBuffer();
-        int i = 0;
-        while (i < a.length) {
-            sbuf.append(a[i++].toString());
-            if (i != a.length)
-                sbuf.append(", ");
-        }
-
-        return sbuf.toString();
-    }
-
-    static class Walker {
-        byte[] info;
-
-        Walker(byte[] attrInfo) {
-            info = attrInfo;
-        }
-
-        final void parameters() throws Exception {
-            int numParam = info[0] & 0xff;
-            parameters(numParam, 1);
-        }
-
-        void parameters(int numParam, int pos) throws Exception {
-            for (int i = 0; i < numParam; ++i)
-                pos = annotationArray(pos);
-        }
-
-        final void annotationArray() throws Exception {
-            annotationArray(0);
-        }
-
-        final int annotationArray(int pos) throws Exception {
-            int num = ByteArray.readU16bit(info, pos);
-            return annotationArray(pos + 2, num);
-        }
-
-        int annotationArray(int pos, int num) throws Exception {
-            for (int i = 0; i < num; ++i)
-                pos = annotation(pos);
-
-            return pos;
-        }
-
-        final int annotation(int pos) throws Exception {
-            int type = ByteArray.readU16bit(info, pos);
-            int numPairs = ByteArray.readU16bit(info, pos + 2);
-            return annotation(pos + 4, type, numPairs);
-        }
-
-        int annotation(int pos, int type, int numPairs) throws Exception {
-            for (int j = 0; j < numPairs; ++j)
-                pos = memberValuePair(pos);
-
-            return pos;
-        }
-
-        final int memberValuePair(int pos) throws Exception {
-            int nameIndex = ByteArray.readU16bit(info, pos);
-            return memberValuePair(pos + 2, nameIndex);
-        }
-
-        int memberValuePair(int pos, int nameIndex) throws Exception {
-            return memberValue(pos);
-        }
-
-        final int memberValue(int pos) throws Exception {
-            int tag = info[pos] & 0xff;
-            if (tag == 'e') {
-                int typeNameIndex = ByteArray.readU16bit(info, pos + 1);
-                int constNameIndex = ByteArray.readU16bit(info, pos + 3);
-                enumMemberValue(typeNameIndex, constNameIndex);
-                return pos + 5;
-            }
-            else if (tag == 'c') {
-                int index = ByteArray.readU16bit(info, pos + 1);
-                classMemberValue(index);
-                return pos + 3;
-            }
-            else if (tag == '@')
-                return annotationMemberValue(pos + 1);
-            else if (tag == '[') {
-                int num = ByteArray.readU16bit(info, pos + 1);
-                return arrayMemberValue(pos + 3, num);
-            }
-            else { // primitive types or String.
-                int index = ByteArray.readU16bit(info, pos + 1);
-                constValueMember(tag, index);
-                return pos + 3;
-            }
-        }
-
-        void constValueMember(int tag, int index) throws Exception {} 
-
-        void enumMemberValue(int typeNameIndex, int constNameIndex)
-            throws Exception {}
-
-        void classMemberValue(int index) throws Exception {}
-
-        int annotationMemberValue(int pos) throws Exception {
-            return annotation(pos);
-        }
-
-        int arrayMemberValue(int pos, int num) throws Exception {
-            for (int i = 0; i < num; ++i) {
-                pos = memberValue(pos);
-            }
-
-            return pos;
-        }
-    }
-
-    static class Copier extends Walker {
-        ByteArrayOutputStream output; 
-        AnnotationsWriter writer;
-        ConstPool srcPool, destPool;
-        Map classnames;
-
-        /**
-         * Constructs a copier.  This copier renames some class names
-         * into the new names specified by <code>map</code> when it copies
-         * an annotation attribute.
-         *
-         * @param info       the source attribute.
-         * @param src        the constant pool of the source class.
-         * @param dest       the constant pool of the destination class.
-         * @param map        pairs of replaced and substituted class names.
-         *                   It can be null.
-         */
-        Copier(byte[] info, ConstPool src, ConstPool dest, Map map) {
-            super(info);
-            output = new ByteArrayOutputStream();
-            writer = new AnnotationsWriter(output, dest);
-            srcPool = src;
-            destPool = dest;
-            classnames = map;
-        }
-
-        byte[] close() throws IOException {
-            writer.close();
-            return output.toByteArray();
-        }
-
-        void parameters(int numParam, int pos) throws Exception {
-            writer.numParameters(numParam);
-            super.parameters(numParam, pos);
-        }
-
-        int annotationArray(int pos, int num) throws Exception {
-            writer.numAnnotations(num);
-            return super.annotationArray(pos, num);
-        }
-
-        int annotation(int pos, int type, int numPairs) throws Exception {
-            writer.annotation(copy(type), numPairs);
-            return super.annotation(pos, type, numPairs);
-        }
-
-        int memberValuePair(int pos, int nameIndex) throws Exception {
-            writer.memberValuePair(copy(nameIndex));
-            return super.memberValuePair(pos, nameIndex);
-        }
-
-        void constValueMember(int tag, int index) throws Exception {
-            writer.constValueIndex(tag, copy(index));
-            super.constValueMember(tag, index);
-        } 
-
-        void enumMemberValue(int typeNameIndex, int constNameIndex)
-            throws Exception
-        {
-            writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex));
-            super.enumMemberValue(typeNameIndex, constNameIndex);
-        }
-
-        void classMemberValue(int index) throws Exception {
-            writer.classInfoIndex(copy(index));
-            super.classMemberValue(index);
-        }
-
-        int annotationMemberValue(int pos) throws Exception {
-            writer.annotationValue();
-            return super.annotationMemberValue(pos);
-        }
-
-        int arrayMemberValue(int pos, int num) throws Exception {
-            writer.arrayValue(num);
-            return super.arrayMemberValue(pos, num);
-        }
-
-        /**
-         * Copies a constant pool entry into the destination constant pool
-         * and returns the index of the copied entry.
-         *
-         * @param srcIndex      the index of the copied entry into the source
-         *                      constant pool. 
-         * @return the index of the copied item into the destination
-         *          constant pool. 
-         */
-        int copy(int srcIndex) {
-            return srcPool.copy(srcIndex, destPool, classnames);
-        }
-    }
-
-    static class Parser extends Walker {
-        ConstPool pool;
-        Annotation[][] allParams;   // all parameters
-        Annotation[] allAnno;       // all annotations
-        Annotation currentAnno;     // current annotation
-        MemberValue memberValue;
-
-        /**
-         * Constructs a parser.  This parser constructs a parse tree of
-         * the annotations.
-         *
-         * @param info       the attribute.
-         * @param src        the constant pool.
-         */
-        Parser(byte[] info, ConstPool cp) {
-            super(info);
-            pool = cp;
-        }
-
-        Annotation[][] parseParameters() throws Exception {
-            parameters();
-            return allParams;
-        }
-
-        Annotation[] parseAnnotations() throws Exception {
-            annotationArray();
-            return allAnno;
-        }
-
-        void parameters(int numParam, int pos) throws Exception {
-            Annotation[][] params = new Annotation[numParam][];
-            for (int i = 0; i < numParam; ++i) {
-                pos = annotationArray(pos);
-                params[i] = allAnno;
-            }
-
-            allParams = params;
-        }
-
-        int annotationArray(int pos, int num) throws Exception {
-            Annotation[] array = new Annotation[num];
-            for (int i = 0; i < num; ++i) {
-                pos = annotation(pos);
-                array[i] = currentAnno;
-            }
-
-            allAnno = array;
-            return pos;
-        }
-
-        int annotation(int pos, int type, int numPairs) throws Exception {
-            currentAnno = new Annotation(type, pool);
-            return super.annotation(pos, type, numPairs);
-        }
-
-        int memberValuePair(int pos, int nameIndex) throws Exception {
-            pos = super.memberValuePair(pos, nameIndex);
-            currentAnno.addMemberValue(nameIndex, memberValue);
-            return pos;
-        }
-
-        void constValueMember(int tag, int index) throws Exception {
-            MemberValue m;
-            ConstPool cp = pool;
-            switch (tag) {
-            case 'B' :
-                m = new ByteMemberValue(index, cp);
-                break;
-            case 'C' :
-                m = new CharMemberValue(index, cp);
-                break;
-            case 'D' :
-                m = new DoubleMemberValue(index, cp);
-                break;
-            case 'F' :
-                m = new FloatMemberValue(index, cp);
-                break;
-            case 'I' :
-                m = new IntegerMemberValue(index, cp);
-                break;
-            case 'J' :
-                m = new LongMemberValue(index, cp);
-                break;
-            case 'S' :
-                m = new ShortMemberValue(index, cp);
-                break;
-            case 'Z' :
-                m = new BooleanMemberValue(index, cp);
-                break;
-            case 's' :
-                m = new StringMemberValue(index, cp);
-                break;
-            default :
-                throw new RuntimeException("unknown tag:" + tag);
-            }
-
-            memberValue = m;
-            super.constValueMember(tag, index);
-        } 
-
-        void enumMemberValue(int typeNameIndex, int constNameIndex)
-            throws Exception
-        {
-            memberValue = new EnumMemberValue(typeNameIndex,
-                                              constNameIndex, pool);
-            super.enumMemberValue(typeNameIndex, constNameIndex);
-        }
-
-        void classMemberValue(int index) throws Exception {
-            memberValue = new ClassMemberValue(index, pool);
-            super.classMemberValue(index);
-        }
-
-        int annotationMemberValue(int pos) throws Exception {
-            Annotation anno = currentAnno;
-            pos = super.annotationMemberValue(pos);
-            memberValue = new AnnotationMemberValue(currentAnno, pool);
-            currentAnno = anno;
-            return pos;
-        }
-
-        int arrayMemberValue(int pos, int num) throws Exception {
-            ArrayMemberValue amv = new ArrayMemberValue(pool);
-            MemberValue[] elements = new MemberValue[num];
-            for (int i = 0; i < num; ++i) {
-                pos = memberValue(pos);
-                elements[i] = memberValue;
-            }
-
-            amv.setValue(elements);
-            memberValue = amv;
-            return pos;
-        }
-    }
+public class AnnotationsAttribute extends AttributeInfo
+{
+   /**
+    * The name of the <code>RuntimeVisibleAnnotations</code> attribute.
+    */
+   public static final String visibleTag = "RuntimeVisibleAnnotations";
+
+   /**
+    * The name of the <code>RuntimeInvisibleAnnotations</code> attribute.
+    */
+   public static final String invisibleTag = "RuntimeInvisibleAnnotations";
+
+   private HashMap annotationMap;
+
+   /**
+    * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>.
+    *
+    * @param cp       constant pool
+    * @param attrname attribute name (<code>visibleTag</code> or
+    *                 <code>invisibleTag</code>).
+    * @param info     the contents of this attribute.  It does not
+    *                 include <code>attribute_name_index</code> or
+    *                 <code>attribute_length</code>.
+    */
+   public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info)
+   {
+      super(cp, attrname, info);
+   }
+
+   /**
+    * Constructs an empty
+    * <code>Runtime(In)VisisbleAnnotations_attribute</code>.
+    * A new annotation can be later added to the created attribute
+    * by <code>setAnnotations()</code>.
+    *
+    * @param cp       constant pool
+    * @param attrname attribute name (<code>visibleTag</code> or
+    *                 <code>invisibleTag</code>).
+    * @see #setAnnotations(Annotation[])
+    */
+   public AnnotationsAttribute(ConstPool cp, String attrname)
+   {
+      this(cp, attrname, new byte[]{0, 0});
+   }
+
+   /**
+    * @param n the attribute name.
+    */
+   AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
+           throws IOException
+   {
+      super(cp, n, in);
+   }
+
+   /**
+    * Returns <code>num_annotations</code>.
+    */
+   public int numAnnotations()
+   {
+      return ByteArray.readU16bit(info, 0);
+   }
+
+   /**
+    * Copies this attribute and returns a new copy.
+    */
+   public AttributeInfo copy(ConstPool newCp, Map classnames)
+   {
+      Copier copier = new Copier(info, constPool, newCp, classnames);
+      try
+      {
+         copier.annotationArray();
+         return new AnnotationsAttribute(newCp, getName(), copier.close());
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException(e.toString());
+      }
+   }
+
+   public Annotation getAnnotation(String type)
+   {
+      Annotation[] annotations = getAnnotations();
+      for (int i = 0; i < annotations.length; i++)
+      {
+         if (annotations[i].getTypeName().equals(type)) return annotations[i];
+      }
+      return null;
+   }
+
+   public void addAnnotation(Annotation annotation)
+   {
+      String type = annotation.getTypeName();
+      Annotation[] annotations = getAnnotations();
+      for (int i = 0; i < annotations.length; i++)
+      {
+         if (annotations[i].getTypeName().equals(type))
+         {
+            annotations[i] = annotation;
+            setAnnotations(annotations);
+            return;
+         }
+      }
+      Annotation[] newlist = new Annotation[annotations.length + 1];
+      System.arraycopy(annotations, 0, newlist, 0, annotations.length);
+      newlist[annotations.length] = annotation;
+      setAnnotations(newlist);
+   }
+
+   /**
+    * Parses the annotations and returns a data structure representing
+    * that parsed annotations.  Note that changes of the node values of the
+    * returned tree are not reflected on the annotations represented by
+    * this object unless the tree is copied back to this object by
+    * <code>setAnnotations()</code>.
+    *
+    * @see #setAnnotations(Annotation[])
+    */
+   public Annotation[] getAnnotations()
+   {
+      try
+      {
+         return new Parser(info, constPool).parseAnnotations();
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException(e.toString());
+      }
+   }
+
+   /**
+    * Changes the annotations represented by this object according to
+    * the given array of <code>Annotation</code> objects.
+    *
+    * @param annotations the data structure representing the
+    *                    new annotations.
+    */
+   public void setAnnotations(Annotation[] annotations)
+   {
+      ByteArrayOutputStream output = new ByteArrayOutputStream();
+      AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
+      try
+      {
+         int n = annotations.length;
+         writer.numAnnotations(n);
+         for (int i = 0; i < n; ++i)
+            annotations[i].write(writer);
+
+         writer.close();
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);      // should never reach here.
+      }
+
+      set(output.toByteArray());
+   }
+
+   /**
+    * Changes the annotations.  A call to this method is equivalent to:
+    * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul>
+    *
+    * @param annotation the data structure representing
+    *                   the new annotation.
+    */
+   public void setAnnotation(Annotation annotation)
+   {
+      setAnnotations(new Annotation[]{annotation});
+   }
+
+   /**
+    * Returns a string representation of this object.
+    */
+   public String toString()
+   {
+      Annotation[] a = getAnnotations();
+      StringBuffer sbuf = new StringBuffer();
+      int i = 0;
+      while (i < a.length)
+      {
+         sbuf.append(a[i++].toString());
+         if (i != a.length)
+            sbuf.append(", ");
+      }
+
+      return sbuf.toString();
+   }
+
+   static class Walker
+   {
+      byte[] info;
+
+      Walker(byte[] attrInfo)
+      {
+         info = attrInfo;
+      }
+
+      final void parameters() throws Exception
+      {
+         int numParam = info[0] & 0xff;
+         parameters(numParam, 1);
+      }
+
+      void parameters(int numParam, int pos) throws Exception
+      {
+         for (int i = 0; i < numParam; ++i)
+            pos = annotationArray(pos);
+      }
+
+      final void annotationArray() throws Exception
+      {
+         annotationArray(0);
+      }
+
+      final int annotationArray(int pos) throws Exception
+      {
+         int num = ByteArray.readU16bit(info, pos);
+         return annotationArray(pos + 2, num);
+      }
+
+      int annotationArray(int pos, int num) throws Exception
+      {
+         for (int i = 0; i < num; ++i)
+            pos = annotation(pos);
+
+         return pos;
+      }
+
+      final int annotation(int pos) throws Exception
+      {
+         int type = ByteArray.readU16bit(info, pos);
+         int numPairs = ByteArray.readU16bit(info, pos + 2);
+         return annotation(pos + 4, type, numPairs);
+      }
+
+      int annotation(int pos, int type, int numPairs) throws Exception
+      {
+         for (int j = 0; j < numPairs; ++j)
+            pos = memberValuePair(pos);
+
+         return pos;
+      }
+
+      final int memberValuePair(int pos) throws Exception
+      {
+         int nameIndex = ByteArray.readU16bit(info, pos);
+         return memberValuePair(pos + 2, nameIndex);
+      }
+
+      int memberValuePair(int pos, int nameIndex) throws Exception
+      {
+         return memberValue(pos);
+      }
+
+      final int memberValue(int pos) throws Exception
+      {
+         int tag = info[pos] & 0xff;
+         if (tag == 'e')
+         {
+            int typeNameIndex = ByteArray.readU16bit(info, pos + 1);
+            int constNameIndex = ByteArray.readU16bit(info, pos + 3);
+            enumMemberValue(typeNameIndex, constNameIndex);
+            return pos + 5;
+         }
+         else if (tag == 'c')
+         {
+            int index = ByteArray.readU16bit(info, pos + 1);
+            classMemberValue(index);
+            return pos + 3;
+         }
+         else if (tag == '@')
+            return annotationMemberValue(pos + 1);
+         else if (tag == '[')
+         {
+            int num = ByteArray.readU16bit(info, pos + 1);
+            return arrayMemberValue(pos + 3, num);
+         }
+         else
+         { // primitive types or String.
+            int index = ByteArray.readU16bit(info, pos + 1);
+            constValueMember(tag, index);
+            return pos + 3;
+         }
+      }
+
+      void constValueMember(int tag, int index) throws Exception
+      {
+      }
+
+      void enumMemberValue(int typeNameIndex, int constNameIndex)
+              throws Exception
+      {
+      }
+
+      void classMemberValue(int index) throws Exception
+      {
+      }
+
+      int annotationMemberValue(int pos) throws Exception
+      {
+         return annotation(pos);
+      }
+
+      int arrayMemberValue(int pos, int num) throws Exception
+      {
+         for (int i = 0; i < num; ++i)
+         {
+            pos = memberValue(pos);
+         }
+
+         return pos;
+      }
+   }
+
+   static class Copier extends Walker
+   {
+      ByteArrayOutputStream output;
+      AnnotationsWriter writer;
+      ConstPool srcPool, destPool;
+      Map classnames;
+
+      /**
+       * Constructs a copier.  This copier renames some class names
+       * into the new names specified by <code>map</code> when it copies
+       * an annotation attribute.
+       *
+       * @param info the source attribute.
+       * @param src  the constant pool of the source class.
+       * @param dest the constant pool of the destination class.
+       * @param map  pairs of replaced and substituted class names.
+       *             It can be null.
+       */
+      Copier(byte[] info, ConstPool src, ConstPool dest, Map map)
+      {
+         super(info);
+         output = new ByteArrayOutputStream();
+         writer = new AnnotationsWriter(output, dest);
+         srcPool = src;
+         destPool = dest;
+         classnames = map;
+      }
+
+      byte[] close() throws IOException
+      {
+         writer.close();
+         return output.toByteArray();
+      }
+
+      void parameters(int numParam, int pos) throws Exception
+      {
+         writer.numParameters(numParam);
+         super.parameters(numParam, pos);
+      }
+
+      int annotationArray(int pos, int num) throws Exception
+      {
+         writer.numAnnotations(num);
+         return super.annotationArray(pos, num);
+      }
+
+      int annotation(int pos, int type, int numPairs) throws Exception
+      {
+         writer.annotation(copy(type), numPairs);
+         return super.annotation(pos, type, numPairs);
+      }
+
+      int memberValuePair(int pos, int nameIndex) throws Exception
+      {
+         writer.memberValuePair(copy(nameIndex));
+         return super.memberValuePair(pos, nameIndex);
+      }
+
+      void constValueMember(int tag, int index) throws Exception
+      {
+         writer.constValueIndex(tag, copy(index));
+         super.constValueMember(tag, index);
+      }
+
+      void enumMemberValue(int typeNameIndex, int constNameIndex)
+              throws Exception
+      {
+         writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex));
+         super.enumMemberValue(typeNameIndex, constNameIndex);
+      }
+
+      void classMemberValue(int index) throws Exception
+      {
+         writer.classInfoIndex(copy(index));
+         super.classMemberValue(index);
+      }
+
+      int annotationMemberValue(int pos) throws Exception
+      {
+         writer.annotationValue();
+         return super.annotationMemberValue(pos);
+      }
+
+      int arrayMemberValue(int pos, int num) throws Exception
+      {
+         writer.arrayValue(num);
+         return super.arrayMemberValue(pos, num);
+      }
+
+      /**
+       * Copies a constant pool entry into the destination constant pool
+       * and returns the index of the copied entry.
+       *
+       * @param srcIndex the index of the copied entry into the source
+       *                 constant pool.
+       * @return the index of the copied item into the destination
+       *         constant pool.
+       */
+      int copy(int srcIndex)
+      {
+         return srcPool.copy(srcIndex, destPool, classnames);
+      }
+   }
+
+   static class Parser extends Walker
+   {
+      ConstPool pool;
+      Annotation[][] allParams;   // all parameters
+      Annotation[] allAnno;       // all annotations
+      Annotation currentAnno;     // current annotation
+      MemberValue memberValue;
+
+      /**
+       * Constructs a parser.  This parser constructs a parse tree of
+       * the annotations.
+       *
+       * @param info the attribute.
+       * @param src  the constant pool.
+       */
+      Parser(byte[] info, ConstPool cp)
+      {
+         super(info);
+         pool = cp;
+      }
+
+      Annotation[][] parseParameters() throws Exception
+      {
+         parameters();
+         return allParams;
+      }
+
+      Annotation[] parseAnnotations() throws Exception
+      {
+         annotationArray();
+         return allAnno;
+      }
+
+      void parameters(int numParam, int pos) throws Exception
+      {
+         Annotation[][] params = new Annotation[numParam][];
+         for (int i = 0; i < numParam; ++i)
+         {
+            pos = annotationArray(pos);
+            params[i] = allAnno;
+         }
+
+         allParams = params;
+      }
+
+      int annotationArray(int pos, int num) throws Exception
+      {
+         Annotation[] array = new Annotation[num];
+         for (int i = 0; i < num; ++i)
+         {
+            pos = annotation(pos);
+            array[i] = currentAnno;
+         }
+
+         allAnno = array;
+         return pos;
+      }
+
+      int annotation(int pos, int type, int numPairs) throws Exception
+      {
+         currentAnno = new Annotation(type, pool);
+         return super.annotation(pos, type, numPairs);
+      }
+
+      int memberValuePair(int pos, int nameIndex) throws Exception
+      {
+         pos = super.memberValuePair(pos, nameIndex);
+         currentAnno.addMemberValue(nameIndex, memberValue);
+         return pos;
+      }
+
+      void constValueMember(int tag, int index) throws Exception
+      {
+         MemberValue m;
+         ConstPool cp = pool;
+         switch (tag)
+         {
+         case 'B':
+            m = new ByteMemberValue(index, cp);
+            break;
+         case 'C':
+            m = new CharMemberValue(index, cp);
+            break;
+         case 'D':
+            m = new DoubleMemberValue(index, cp);
+            break;
+         case 'F':
+            m = new FloatMemberValue(index, cp);
+            break;
+         case 'I':
+            m = new IntegerMemberValue(index, cp);
+            break;
+         case 'J':
+            m = new LongMemberValue(index, cp);
+            break;
+         case 'S':
+            m = new ShortMemberValue(index, cp);
+            break;
+         case 'Z':
+            m = new BooleanMemberValue(index, cp);
+            break;
+         case 's':
+            m = new StringMemberValue(index, cp);
+            break;
+         default :
+            throw new RuntimeException("unknown tag:" + tag);
+         }
+
+         memberValue = m;
+         super.constValueMember(tag, index);
+      }
+
+      void enumMemberValue(int typeNameIndex, int constNameIndex)
+              throws Exception
+      {
+         memberValue = new EnumMemberValue(typeNameIndex,
+                 constNameIndex, pool);
+         super.enumMemberValue(typeNameIndex, constNameIndex);
+      }
+
+      void classMemberValue(int index) throws Exception
+      {
+         memberValue = new ClassMemberValue(index, pool);
+         super.classMemberValue(index);
+      }
+
+      int annotationMemberValue(int pos) throws Exception
+      {
+         Annotation anno = currentAnno;
+         pos = super.annotationMemberValue(pos);
+         memberValue = new AnnotationMemberValue(currentAnno, pool);
+         currentAnno = anno;
+         return pos;
+      }
+
+      int arrayMemberValue(int pos, int num) throws Exception
+      {
+         ArrayMemberValue amv = new ArrayMemberValue(pool);
+         MemberValue[] elements = new MemberValue[num];
+         for (int i = 0; i < num; ++i)
+         {
+            pos = memberValue(pos);
+            elements[i] = memberValue;
+         }
+
+         amv.setValue(elements);
+         memberValue = amv;
+         return pos;
+      }
+   }
 }
index 9e866578ff8a07f4ec76d7c1447a4a29956e1150..b0744942307c41f4b11748217bd9f13a18580c1f 100644 (file)
@@ -18,9 +18,9 @@ package javassist.bytecode;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.util.Map;
-import java.util.List;
 import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 
 /**
  * <code>method_info</code> structure.
@@ -28,364 +28,395 @@ 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
-
-    /**
-     * 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.
-     * The initial value of <code>access_flags</code> is zero.
-     *
-     * @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);
-    }
-
-    void prune(ConstPool cp) {
-        attribute = null;
-        name = cp.addUtf8Info(getName());
-        descriptor = cp.addUtf8Info(getDescriptor());
-        constPool = cp;
-    }
-
-    /**
-     * 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.
-     * A new element can be added to the returned list
-     * and an existing element can be removed from the list.
-     *
-     * @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);
-    }
-
-    /**
-     * Returns an Exceptions attribute.
-     *
-     * @return          an Exceptions attribute
-     *                  or null if it is not specified.
-     */
-    public ExceptionsAttribute getExceptionsAttribute() {
-        AttributeInfo info
-            = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag);
-        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.tag);
-        return (CodeAttribute)info;
-    }
-
-    /**
-     * Removes an Exception attribute.
-     */
-    public void removeExceptionsAttribute() {
-        AttributeInfo.remove(attribute, ExceptionsAttribute.tag);
-    }
-
-    /**
-     * 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.tag);
-    }
-
-    /**
-     * 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
+
+   /**
+    * 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.
+    * The initial value of <code>access_flags</code> is zero.
+    *
+    * @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/>
+    * <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);
+   }
+
+   void prune(ConstPool cp)
+   {
+      new Exception("****** pruned *****").printStackTrace();
+      attribute = null;
+      name = cp.addUtf8Info(getName());
+      descriptor = cp.addUtf8Info(getDescriptor());
+      constPool = cp;
+   }
+
+   /**
+    * 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.
+    * A new element can be added to the returned list
+    * and an existing element can be removed from the list.
+    *
+    * @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);
+   }
+
+   /**
+    * Returns an Exceptions attribute.
+    *
+    * @return an Exceptions attribute
+    *         or null if it is not specified.
+    */
+   public ExceptionsAttribute getExceptionsAttribute()
+   {
+      AttributeInfo info
+              = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag);
+      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.tag);
+      return (CodeAttribute) info;
+   }
+
+   /**
+    * Removes an Exception attribute.
+    */
+   public void removeExceptionsAttribute()
+   {
+      AttributeInfo.remove(attribute, ExceptionsAttribute.tag);
+   }
+
+   /**
+    * Adds an Exception attribute.
+    * <p/>
+    * <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.tag);
+   }
+
+   /**
+    * Adds a Code attribute.
+    * <p/>
+    * <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/>
+    * <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/>
+    * <p>This method should be called when the super class
+    * of the class declaring this method is changed.
+    * <p/>
+    * <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 78a6217dd72a1ec5faa77651b3d0e6be0d12a56f..09a1075bc7d58169dab2c95bc1dc6a11760f6393 100644 (file)
@@ -17,6 +17,7 @@ package javassist.bytecode.annotation;
 
 import javassist.bytecode.ConstPool;
 import javassist.bytecode.Descriptor;
+
 import java.io.IOException;
 
 /**
@@ -25,72 +26,83 @@ import java.io.IOException;
  * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
  * @author Shigeru Chiba
  */
-public class ClassMemberValue extends MemberValue {
-    int valueIndex;
+public class ClassMemberValue extends MemberValue
+{
+   int valueIndex;
 
-    /**
-     * Constructs a string constant value.  The initial value is specified
-     * by the constant pool entry at the given index.
-     *
-     * @param index     the index of a CONSTANT_Utf8_info structure.
-     */
-    public ClassMemberValue(int index, ConstPool cp) {
-        super('c', cp);
-        this.valueIndex = index;
-    }
+   /**
+    * Constructs a string constant value.  The initial value is specified
+    * by the constant pool entry at the given index.
+    *
+    * @param index the index of a CONSTANT_Utf8_info structure.
+    */
+   public ClassMemberValue(int index, ConstPool cp)
+   {
+      super('c', cp);
+      this.valueIndex = index;
+   }
 
-    /**
-     * Constructs a string constant value.
-     *
-     * @param className         the initial value.
-     */
-    public ClassMemberValue(String className, ConstPool cp) {
-        super('c', cp);
-        setValue(className);
-    }
+   /**
+    * Constructs a string constant value.
+    *
+    * @param className the initial value.
+    */
+   public ClassMemberValue(String className, ConstPool cp)
+   {
+      super('c', cp);
+      setValue(className);
+   }
 
-    /**
-     * Constructs a string constant value.
-     * The initial value is java.lang.Class.
-     */
-    public ClassMemberValue(ConstPool cp) {
-        super('c', cp);
-        setValue("java.lang.Class");
-    }
+   /**
+    * Constructs a string constant value.
+    * The initial value is java.lang.Class.
+    */
+   public ClassMemberValue(ConstPool cp)
+   {
+      super('c', cp);
+      setValue("java.lang.Class");
+   }
 
-    /**
-     * Obtains the value of the member.
-     *
-     * @return fully-qualified class name.
-     */
-    public String getValue() {
-        return Descriptor.toClassName(cp.getUtf8Info(valueIndex));
-    }
+   /**
+    * Obtains the value of the member.
+    *
+    * @return fully-qualified class name.
+    */
+   public String getValue()
+   {
+      String v = cp.getUtf8Info(valueIndex);
+      return Descriptor.toClassName(v);
+   }
 
-    /**
-     * Sets the value of the member.
-     *
-     * @param newClassName      fully-qualified class name.
-     */
-    public void setValue(String newClassName) {
-        valueIndex = cp.addUtf8Info(Descriptor.of(newClassName));
-    }
+   /**
+    * Sets the value of the member.
+    *
+    * @param newClassName fully-qualified class name.
+    */
+   public void setValue(String newClassName)
+   {
+      String setTo = Descriptor.of(newClassName);
+      valueIndex = cp.addUtf8Info(setTo);
+   }
 
-    /**
-     * Obtains the string representation of this object.
-     */
-    public String toString() {
-        return "<" + getValue() + " class>";
-    }
+   /**
+    * Obtains the string representation of this object.
+    */
+   public String toString()
+   {
+      return "<" + getValue() + " class>";
+   }
 
-    void write(AnnotationsWriter writer) throws IOException {
-        writer.constValueIndex(getValue());
-    }
+   void write(AnnotationsWriter writer) throws IOException
+   {
+      writer.classInfoIndex(valueIndex);
+   }
 
-    /**
-     * Accepts a visitor.
-     */
-    public void accept(MemberValueVisitor visitor) {
-        visitor.visitClassMemberValue(this);
-    }
+   /**
+    * Accepts a visitor.
+    */
+   public void accept(MemberValueVisitor visitor)
+   {
+      visitor.visitClassMemberValue(this);
+   }
 }