]> source.dussan.org Git - javassist.git/commitdiff
Array initializer supports and better annotation supports.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 25 Aug 2005 05:08:05 +0000 (05:08 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 25 Aug 2005 05:08:05 +0000 (05:08 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@196 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

31 files changed:
Readme.html
build.xml
src/main/javassist/CtBehavior.java
src/main/javassist/CtClass.java
src/main/javassist/CtClassType.java
src/main/javassist/CtField.java
src/main/javassist/CtMember.java
src/main/javassist/bytecode/annotation/Annotation.java
src/main/javassist/bytecode/annotation/AnnotationImpl.java [new file with mode: 0644]
src/main/javassist/bytecode/annotation/AnnotationMemberValue.java
src/main/javassist/bytecode/annotation/ArrayMemberValue.java
src/main/javassist/bytecode/annotation/BooleanMemberValue.java
src/main/javassist/bytecode/annotation/ByteMemberValue.java
src/main/javassist/bytecode/annotation/CharMemberValue.java
src/main/javassist/bytecode/annotation/ClassMemberValue.java
src/main/javassist/bytecode/annotation/DoubleMemberValue.java
src/main/javassist/bytecode/annotation/EnumMemberValue.java
src/main/javassist/bytecode/annotation/FloatMemberValue.java
src/main/javassist/bytecode/annotation/IntegerMemberValue.java
src/main/javassist/bytecode/annotation/LongMemberValue.java
src/main/javassist/bytecode/annotation/MemberValue.java
src/main/javassist/bytecode/annotation/ShortMemberValue.java
src/main/javassist/bytecode/annotation/StringMemberValue.java
src/main/javassist/compiler/CodeGen.java
src/main/javassist/compiler/MemberCodeGen.java
src/main/javassist/compiler/Parser.java
src/main/javassist/compiler/TypeChecker.java
src/main/javassist/compiler/ast/ArrayInit.java [new file with mode: 0644]
src/main/javassist/compiler/ast/NewExpr.java
src/main/javassist/compiler/ast/Visitor.java
tutorial/tutorial2.html

index 7227b9bad38867eaa8f9bfeee52d5f71f91bc0bf..9ea78d47cd46b5b3532dceea85e0d2630abcab69 100644 (file)
@@ -282,10 +282,14 @@ see javassist.Dump.
 
 <h2>Changes</h2>
 
-<p>- version 3.1
+<p>- version 3.1 RC1
 
 <ul>
+  <li>Better annotation supports.  See <code>CtClass.getAnnotations()</code>
   <li>javassist.tool.HotSwapper was added.
+  <li>javassist.ClassPool.importPackage() was added.
+  <li>The compiler now accepts array initializers
+    (only one dimensional arrays).
   <li>javassist.Dump was moved to javassist.tool.Dump.
 </ul>
 
index 9663a986539b2dc472c53a3f9de930343e53e130..3c9a62610e6a84f4d553562122a617b5f3ddbb03 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
 
 <project name="javassist" default="jar" basedir=".">
 
-  <property name="dist-version" value="javassist-3.1"/>
+  <property name="dist-version" value="javassist-3.1RC1"/>
 
   <property environment="env"/>
   <property name="target.jar" value="javassist.jar"/>
index 791457c4dbc507d817c82b55e46ac8e0797732ef..a8baaf8c4cd0c2ce2739a343bcad36bb1b111ff2 100644 (file)
@@ -80,6 +80,22 @@ public abstract class CtBehavior extends CtMember {
         methodInfo.setAccessFlags(AccessFlag.of(mod));
     }
 
+    /**
+     * Returns the annotations associated with this method or constructor.
+     *
+     * @return an array of annotation-type objects.
+     * @see CtMember#getAnnotations()
+     */
+    public Object[] getAnnotations() throws ClassNotFoundException {
+        MethodInfo mi = getMethodInfo2();
+        AnnotationsAttribute ainfo = (AnnotationsAttribute)
+                    mi.getAttribute(AnnotationsAttribute.invisibleTag);  
+        AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
+                    mi.getAttribute(AnnotationsAttribute.visibleTag);  
+        return CtClassType.toAnnotationType(getDeclaringClass().getClassPool(),
+                                            ainfo, ainfo2);
+    }
+
     /**
      * Obtains parameter types of this method/constructor.
      */
index b2d6ff1027d7c1f119f6d5a77404a9d0898363c2..a96701b22682cee934fb3538b61b9df75a17c31c 100644 (file)
@@ -29,7 +29,15 @@ import javassist.bytecode.Descriptor;
 import javassist.bytecode.Opcode;
 import javassist.expr.ExprEditor;
 
-// Subclasses of CtClass: CtClassType, CtPrimitiveType, and CtArray
+/* Note:
+ *
+ * This class is an abstract class and several methods just return null
+ * or throw an exception.  Those methods are overridden in subclasses
+ * of this class.  Read the source code of CtClassType if you are
+ * interested in the implementation of Javassist.
+ *
+ * Subclasses of CtClass are CtClassType, CtPrimitiveType, and CtArray.
+ */
 
 /**
  * An instance of <code>CtClass</code> represents a class.
@@ -418,6 +426,19 @@ public abstract class CtClass {
         return 0;
     }
 
+    /**
+     * Returns the annotations associated with this class.
+     * For example, if an annotation <code>@Author</code> is associated
+     * with this class, the returned array contains an <code>Author</code>
+     * object.  The member values can be obtained by calling methods on
+     * the <code>Author</code> object.
+     *
+     * @return an array of annotation-type objects.
+     */
+    public Object[] getAnnotations() throws ClassNotFoundException {
+        return new Object[0];
+    }
+
     /**
      * Sets the modifiers.
      *
@@ -872,7 +893,7 @@ public abstract class CtClass {
      * <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.
+     * expression adds an attribute <code>info</code> to a class file.
      *
      * <ul><pre>
      * getClassFile().addAttribute(info)
index b400d8b1e38dcab3838505798b62ace0493574fe..d598940652a621838171fab9b826fdd3961ca26d 100644 (file)
@@ -28,6 +28,7 @@ import java.util.Hashtable;
 import java.util.List;
 import javassist.bytecode.AccessFlag;
 import javassist.bytecode.AttributeInfo;
+import javassist.bytecode.AnnotationsAttribute;
 import javassist.bytecode.BadBytecode;
 import javassist.bytecode.Bytecode;
 import javassist.bytecode.ClassFile;
@@ -40,6 +41,7 @@ import javassist.bytecode.EnclosingMethodAttribute;
 import javassist.bytecode.FieldInfo;
 import javassist.bytecode.InnerClassesAttribute;
 import javassist.bytecode.MethodInfo;
+import javassist.bytecode.annotation.Annotation;
 import javassist.compiler.AccessorMaker;
 import javassist.compiler.CompileError;
 import javassist.compiler.Javac;
@@ -357,6 +359,49 @@ class CtClassType extends CtClass {
         getClassFile2().setAccessFlags(acc);
     }
 
+    public Object[] getAnnotations() throws ClassNotFoundException {
+        ClassFile cf = getClassFile2();
+        AnnotationsAttribute ainfo = (AnnotationsAttribute)
+                    cf.getAttribute(AnnotationsAttribute.invisibleTag);  
+        AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
+                    cf.getAttribute(AnnotationsAttribute.visibleTag);  
+        return toAnnotationType(getClassPool(), ainfo, ainfo2);
+    }
+
+    static Object[] toAnnotationType(ClassPool cp, AnnotationsAttribute a1,
+                                     AnnotationsAttribute a2) throws ClassNotFoundException {
+        Annotation[] anno1, anno2;
+        int size1, size2;
+
+        if (a1 == null) {
+            anno1 = null;
+            size1 = 0;
+        }
+        else {
+            anno1 = a1.getAnnotations();
+            size1 = anno1.length;
+        }
+
+        if (a2 == null) {
+            anno2 = null;
+            size2 = 0;
+        }
+        else {
+            anno2 = a2.getAnnotations();
+            size2 = anno2.length;
+        }
+
+        Object[] result = new Object[size1 + size2];
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        for (int i = 0; i < size1; i++)
+            result[i] = anno1[i].toAnnotationType(cl, cp);
+
+        for (int j = 0; j < size2; j++)
+            result[j + size1] = anno2[j].toAnnotationType(cl, cp);
+
+        return result;
+    }
+
     public boolean subclassOf(CtClass superclass) {
         if (superclass == null)
             return false;
index 710f8c50a2b0737ab304c607d891b1ff643a486e..f4f2986a84d3b0d71330eb74ffcf85131028f4da 100644 (file)
@@ -217,6 +217,22 @@ public class CtField extends CtMember {
         fieldInfo.setAccessFlags(AccessFlag.of(mod));
     }
 
+    /**
+     * Returns the annotations associated with this field.
+     *
+     * @return an array of annotation-type objects.
+     * @see CtMember#getAnnotations()
+     */
+    public Object[] getAnnotations() throws ClassNotFoundException {
+        FieldInfo fi = getFieldInfo2();
+        AnnotationsAttribute ainfo = (AnnotationsAttribute)
+                    fi.getAttribute(AnnotationsAttribute.invisibleTag);  
+        AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
+                    fi.getAttribute(AnnotationsAttribute.visibleTag);  
+        return CtClassType.toAnnotationType(getDeclaringClass().getClassPool(),
+                                            ainfo, ainfo2);
+    }
+
     /**
      * Returns the type of the field.
      */
index ee8aadbcaeb1f2f202c541781871f77d1fb3a2ec..d6bd14f1e8b47a7446be33d11861812061be5f86 100644 (file)
@@ -109,6 +109,18 @@ public abstract class CtMember {
      */
     public abstract void setModifiers(int mod);
 
+    /**
+     * Returns the annotations associated with this member.
+     * For example, if an annotation <code>@Author</code> is associated
+     * with this member, the returned array contains an <code>Author</code>
+     * object.  The member values can be obtained by calling methods on
+     * the <code>Author</code> object.
+     *
+     * @return an array of annotation-type objects.
+     * @see CtClass#getAnnotations()
+     */
+    public abstract Object[] getAnnotations() throws ClassNotFoundException;
+
     /**
      * Obtains the name of the member.
      *
index f4f8ac61425d2cdbcaaee655c2b1f33270659232..9971fada127a5d39eeace598b6f633a3a2eec489 100644 (file)
@@ -17,6 +17,7 @@ package javassist.bytecode.annotation;
 
 import javassist.bytecode.ConstPool;
 import javassist.bytecode.Descriptor;
+import javassist.ClassPool;
 import javassist.CtClass;
 import javassist.CtMethod;
 
@@ -252,7 +253,7 @@ public class Annotation {
      * @return null if the member cannot be found or if the value is
      * the default value.
      *
-     * @see AnnotationDefaultAttribute
+     * @see javassist.bytecode.AnnotationDefaultAttribute
      */
     public MemberValue getMemberValue(String name) {
         if (members == null)
@@ -266,6 +267,22 @@ public class Annotation {
         }
     }
 
+    /**
+     * Constructs an annotation-type object representing this annotation.
+     * For example, if this annotation represents <code>@Author</code>,
+     * this method returns an <code>Author</code> object.
+     * 
+     * @param cl        class loader for loading an annotation type.
+     * @param cp        class pool for obtaining class files.
+     */
+    public Object toAnnotationType(ClassLoader cl, ClassPool cp)
+        throws ClassNotFoundException
+    {
+        return AnnotationImpl.make(cl,
+                        MemberValue.loadClass(cl, getTypeName()),
+                        cp, this);
+    }
+
     /**
      * Writes this annotation.
      *
diff --git a/src/main/javassist/bytecode/annotation/AnnotationImpl.java b/src/main/javassist/bytecode/annotation/AnnotationImpl.java
new file mode 100644 (file)
index 0000000..f81b7b4
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.bytecode.annotation;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.NotFoundException;
+import javassist.bytecode.AnnotationDefaultAttribute;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.MethodInfo;
+
+import java.lang.reflect.*;
+
+class AnnotationImpl implements InvocationHandler {
+    private Annotation annotation;
+    private ClassPool pool;
+    private ClassLoader classLoader;
+
+    /**
+     * Constructs an annotation object.
+     *
+     * @param cl        class loader for obtaining annotation types.
+     * @param clazz     the annotation type.
+     * @param cp        class pool for containing an annotation
+     *                  type (or null).
+     * @param anon      the annotation.
+     */
+    public static Object make(ClassLoader cl, Class clazz, ClassPool cp,
+                              Annotation anon) {
+        AnnotationImpl handler = new AnnotationImpl(anon, cp, cl);
+        return Proxy.newProxyInstance(cl, new Class[] { clazz }, handler);
+    }
+
+    private AnnotationImpl(Annotation a, ClassPool cp, ClassLoader loader) {
+        annotation = a;
+        pool = cp;
+        classLoader = loader;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable
+    {
+        String name = method.getName();
+        MemberValue mv = annotation.getMemberValue(name);
+        if (mv == null)
+            return getDefault(name);
+        else
+            return mv.getValue(classLoader, pool);
+    }
+
+    private Object getDefault(String name)
+        throws ClassNotFoundException, RuntimeException
+    {
+        String classname = annotation.getTypeName();
+        if (pool != null)
+            try {
+                CtClass cc = pool.get(classname);
+                ClassFile cf = cc.getClassFile2();
+                MethodInfo minfo = cf.getMethod(name);
+                if (minfo != null) {
+                    AnnotationDefaultAttribute ainfo
+                        = (AnnotationDefaultAttribute)
+                          minfo.getAttribute(AnnotationDefaultAttribute.tag);
+                    if (ainfo != null) {
+                        MemberValue mv = ainfo.getDefaultValue();
+                        return mv.getValue(classLoader, pool);
+                    }
+                }
+            }
+            catch (NotFoundException e) {
+                throw new RuntimeException("cannot find a class file: "
+                                           + classname);
+            }
+
+        throw new RuntimeException("no default value: " + classname + "."
+                                   + name + "()");
+    }
+}
index 92b3e2d4876ac3e284079d2fa7f0448ca95b09ea..73da1637b679eb2b06f9e88699d4be621846bbff 100644 (file)
@@ -14,6 +14,7 @@
  */
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -42,6 +43,19 @@ public class AnnotationMemberValue extends MemberValue {
         value = a;
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp)
+        throws ClassNotFoundException
+    {
+        return AnnotationImpl.make(cl, getType(cl), cp, value);
+    }
+
+    Class getType(ClassLoader cl) throws ClassNotFoundException {
+        if (value == null)
+            throw new ClassNotFoundException("no type specified");
+        else
+            return loadClass(cl, value.getTypeName());
+    }
+
     /**
      * Obtains the value.
      */
index 351ffc56cce86b9e997bfc9c78037316534cd423..dd586bb331674449f43105c46b2ebbcc5acf6b33 100644 (file)
  */
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
+import java.lang.reflect.Array;
 
 /**
  * Array member.
@@ -47,6 +49,26 @@ public class ArrayMemberValue extends MemberValue {
         values = null;
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) throws ClassNotFoundException {
+        if (type == null || values == null)
+            throw new ClassNotFoundException("no array elements specified");
+
+        int size = values.length;
+        Object a = Array.newInstance(type.getType(cl), size);
+        for (int i = 0; i < size; i++)
+            Array.set(a, i, values[i].getValue(cl, cp));
+
+        return a;
+    }
+
+    Class getType(ClassLoader cl) throws ClassNotFoundException {
+        if (type == null)
+            throw new ClassNotFoundException("no array type specified");
+
+        Object a = Array.newInstance(type.getType(cl), 0);
+        return a.getClass();
+    }
+
     /**
      * Obtains the type of the elements.
      *
index 4f6507e5822e6369009132e9826232ed4eb0d4df..7df117d76315357a239107cdb6f83be950550d41 100644 (file)
@@ -14,6 +14,7 @@
  */
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -55,6 +56,14 @@ public class BooleanMemberValue extends MemberValue {
         setValue(false);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Boolean(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return boolean.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 043f1d2186b9fc4f3789343c99aaeb3b6630bc07..3b8920103bc6ff00193e86c3b47365e1b7cbca4a 100644 (file)
@@ -14,6 +14,7 @@
  */
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -55,6 +56,14 @@ public class ByteMemberValue extends MemberValue {
         setValue((byte)0);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Byte(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return byte.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index c01b7b78c2edaaaadc46ffe89b739ce593f38a8e..8d056d8b2ad04b1193fc1012974aa309f0f54a3b 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -56,6 +57,14 @@ public class CharMemberValue extends MemberValue {
         setValue('\0');
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Character(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return char.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 90da2c41b6e517974b3ddf9ae67435e38bcc6f20..f5f2fe67a348105f9e6155bfe2e2208a76239ced 100644 (file)
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import javassist.bytecode.Descriptor;
 import java.io.IOException;
 
 /**
- * String constant value.
+ * Class value.
  *
  * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
  * @author Shigeru Chiba
@@ -29,7 +30,7 @@ public class ClassMemberValue extends MemberValue {
     int valueIndex;
 
     /**
-     * Constructs a string constant value.  The initial value is specified
+     * Constructs a class 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.
@@ -40,7 +41,7 @@ public class ClassMemberValue extends MemberValue {
     }
 
     /**
-     * Constructs a string constant value.
+     * Constructs a class value.
      *
      * @param className         the initial value.
      */
@@ -50,7 +51,7 @@ public class ClassMemberValue extends MemberValue {
     }
 
     /**
-     * Constructs a string constant value.
+     * Constructs a class value.
      * The initial value is java.lang.Class.
      */
     public ClassMemberValue(ConstPool cp) {
@@ -58,6 +59,16 @@ public class ClassMemberValue extends MemberValue {
         setValue("java.lang.Class");
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp)
+        throws ClassNotFoundException
+    {
+        return loadClass(cl, getValue());
+    }
+
+    Class getType(ClassLoader cl) throws ClassNotFoundException {
+        return loadClass(cl, "java.lang.Class");
+    }
+
     /**
      * Obtains the value of the member.
      *
index 131e35f82f02b25963b6352436a9459dbbe116a6..7c987875106e7a91d98c87ab229e3506319fae82 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -23,7 +24,7 @@ import java.io.IOException;
  *
  * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
  * @author Shigeru Chiba
- * @version $Revision: 1.5 $
+ * @version $Revision: 1.6 $
  */
 public class DoubleMemberValue extends MemberValue {
     int valueIndex;
@@ -57,6 +58,14 @@ public class DoubleMemberValue extends MemberValue {
         setValue(0.0);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Double(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return double.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index cf6263a76944d2f59ff6bf7c0cb71988ee034e3e..77e07c27a396f52ef83fa7518d623ace5a3b767a 100644 (file)
@@ -16,6 +16,8 @@
 package javassist.bytecode.annotation;
 
 import java.io.IOException;
+
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import javassist.bytecode.Descriptor;
 
@@ -52,6 +54,24 @@ public class EnumMemberValue extends MemberValue {
         typeIndex = valueIndex = 0;
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp)
+        throws ClassNotFoundException
+    {
+        try {
+            return getType(cl).getField(getValue()).get(null);
+        }
+        catch (NoSuchFieldException e) {
+            throw new ClassNotFoundException(getType() + "." + getValue());
+        }
+        catch (IllegalAccessException e) {
+            throw new ClassNotFoundException(getType() + "." + getValue());
+        }
+    }
+
+    Class getType(ClassLoader cl) throws ClassNotFoundException {
+        return loadClass(cl, getType());
+    }
+
     /**
      * Obtains the enum type name.
      *
index 87e12ab7cceec8539b2c378ca9e3f34322458e3d..622a9420210676fea829ad6b6954035a6ba5453f 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -23,7 +24,7 @@ import java.io.IOException;
  *
  * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
  * @author Shigeru Chiba
- * @version $Revision: 1.5 $
+ * @version $Revision: 1.6 $
  */
 public class FloatMemberValue extends MemberValue {
     int valueIndex;
@@ -57,6 +58,14 @@ public class FloatMemberValue extends MemberValue {
         setValue(0.0F);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Float(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return float.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index e88462764a0cf744ec517f6e5e2fa94b87853842..949f3752f9f5de2dd46447e6257fcc6ebb0c1333 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -62,6 +63,14 @@ public class IntegerMemberValue extends MemberValue {
         setValue(0);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Integer(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return int.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 4842792f81a40098c91145d5195ff62e95aca66d..a0dd13ad0f925f527ab78138202ea99a75e33aaf 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -56,6 +57,14 @@ public class LongMemberValue extends MemberValue {
         setValue(0L);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Long(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return long.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 84d0eb38a31e81a04c427db6d40a688c7e66b7ca..8ee6ce9ab291c23576d1ac3d74d843280220ec55 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -34,6 +35,21 @@ public abstract class MemberValue {
         this.tag = tag;
     }
 
+    /**
+     * Returns the value.  If the value type is a primitive type, the
+     * returned value is boxed.
+     */
+    abstract Object getValue(ClassLoader cl, ClassPool cp)
+        throws ClassNotFoundException;
+
+    abstract Class getType(ClassLoader cl) throws ClassNotFoundException;
+
+    static Class loadClass(ClassLoader cl, String classname)
+        throws ClassNotFoundException
+    {
+        return Class.forName(classname, true, cl);
+    }
+
     /**
      * Accepts a visitor.
      */
index fc0a1702cab9d65245f3cf9da1ecdda605f8fa59..7d38f4b4c184c6c8939a51ab27ff67c43653e844 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -56,6 +57,14 @@ public class ShortMemberValue extends MemberValue {
         setValue((short)0);
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return new Short(getValue());
+    }
+
+    Class getType(ClassLoader cl) {
+        return short.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 4a32e433bb1990f91f57160005ff4e220b71f5f7..80cb5e3dce9ddd97481d54bd424a78f39bf66f60 100644 (file)
@@ -15,6 +15,7 @@
 
 package javassist.bytecode.annotation;
 
+import javassist.ClassPool;
 import javassist.bytecode.ConstPool;
 import java.io.IOException;
 
@@ -56,6 +57,14 @@ public class StringMemberValue extends MemberValue {
         setValue("");
     }
 
+    Object getValue(ClassLoader cl, ClassPool cp) {
+        return getValue();
+    }
+
+    Class getType(ClassLoader cl) {
+        return String.class;
+    }
+
     /**
      * Obtains the value of the member.
      */
index 9b401804551cdde356c56574202d657d3495d655..6739c17ab5714aa1a4ccbf3c450af8bf3d536c8b 100644 (file)
@@ -709,13 +709,15 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
          */
         ASTree init = d.getInitializer();
         if (init != null) {
-            doTypeCheck(init);        
+            doTypeCheck(init);
             atVariableAssign(null, '=', null, d, init, false);
         }
     }
 
     public abstract void atNewExpr(NewExpr n) throws CompileError;
 
+    public abstract void atArrayInit(ArrayInit init) throws CompileError;
+
     public void atAssignExpr(AssignExpr expr) throws CompileError {
         atAssignExpr(expr, true);
     }
@@ -770,7 +772,11 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
         if (op != '=')
             atVariable(var);
 
-        atAssignCore(expr, op, right, varType, varArray, varClass);
+        // expr is null if the caller is atDeclarator().
+        if (expr == null && right instanceof ArrayInit)
+            atArrayVariableAssign((ArrayInit)right, varType, varArray, varClass);
+        else
+            atAssignCore(expr, op, right, varType, varArray, varClass);
 
         if (doDup)
             if (is2word(varType, varArray))
@@ -796,6 +802,9 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
         className = varClass;
     }
 
+    protected abstract void atArrayVariableAssign(ArrayInit init,
+            int varType, int varArray, String varClass) throws CompileError;
+
     private void atArrayAssign(Expr expr, int op, Expr array,
                         ASTree right, boolean doDup) throws CompileError
     {
index 8802320243672ebd8011082ea15dccc2fc68ae09..ae586d685ed25032e6f41c7d591ed52957b61ebe 100644 (file)
@@ -18,6 +18,7 @@ package javassist.compiler;
 import javassist.*;
 import javassist.bytecode.*;
 import javassist.compiler.ast.*;
+
 import java.util.ArrayList;
 
 /* Code generator methods depending on javassist.* classes.
@@ -29,8 +30,7 @@ public class MemberCodeGen extends CodeGen {
 
     protected boolean resultStatic;
 
-    public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp)
-    {
+    public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
         super(b);
         resolver = new MemberResolver(cp);
         thisClass = cc;
@@ -239,26 +239,46 @@ public class MemberCodeGen extends CodeGen {
     }
 
     public void atNewArrayExpr(NewExpr expr) throws CompileError {
-        if (expr.getInitializer() != null)
-            throw new CompileError("array initializer is not supported");
-
         int type = expr.getArrayType();
         ASTList size = expr.getArraySize();
         ASTList classname = expr.getClassName();
+        ArrayInit init = expr.getInitializer();
         if (size.length() > 1) {
+            if (init != null)
+                throw new CompileError(
+                        "sorry, multi-dimensional array initializer " +
+                        "for new is not supported");
+
             atMultiNewArray(type, classname, size);
             return;
         }
 
-        size.head().accept(this);
-        exprType = type;
-        arrayDim = 1;
+        ASTree sizeExpr = size.head();
+        atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init);
+    }
+
+    private void atNewArrayExpr2(int type, ASTree sizeExpr,
+                        String jvmClassname, ArrayInit init) throws CompileError {
+        if (init == null)
+            if (sizeExpr == null)
+                throw new CompileError("no array size");
+            else
+                sizeExpr.accept(this);
+        else
+            if (sizeExpr == null) {
+                int s = init.length();
+                bytecode.addIconst(s);
+            }
+            else
+                throw new CompileError("unnecessary array size specified for new");
+
+        String elementClass;
         if (type == CLASS) {
-            className = resolveClassName(classname);
-            bytecode.addAnewarray(MemberResolver.jvmToJavaName(className));
+            elementClass = resolveClassName(jvmClassname);
+            bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass));
         }
         else {
-            className = null;
+            elementClass = null;
             int atype = 0;
             switch (type) {
             case BOOLEAN :
@@ -293,12 +313,40 @@ public class MemberCodeGen extends CodeGen {
             bytecode.addOpcode(NEWARRAY);
             bytecode.add(atype);
         }
+
+        if (init != null) {
+            int s = init.length();
+            ASTList list = init;
+            for (int i = 0; i < s; i++) {
+                bytecode.addOpcode(DUP);
+                bytecode.addIconst(i);
+                list.head().accept(this);
+                if (!isRefType(type))
+                    atNumCastExpr(exprType, type);
+
+                bytecode.addOpcode(getArrayWriteOp(type, 0));
+                list = list.tail();
+            }
+        }
+
+        exprType = type;
+        arrayDim = 1;
+        className = elementClass;
     }
 
     private static void badNewExpr() throws CompileError {
         throw new CompileError("bad new expression");
     }
 
+    protected void atArrayVariableAssign(ArrayInit init, int varType,
+                                         int varArray, String varClass) throws CompileError {
+        atNewArrayExpr2(varType, null, varClass, init);
+    }
+
+    public void atArrayInit(ArrayInit init) throws CompileError {
+        throw new CompileError("array initializer is not supported");
+    }
+
     protected void atMultiNewArray(int type, ASTList classname, ASTList size)
         throws CompileError
     {
index e1a0d5b273a09a5a5c205ff3d5f175971c41fe7d..5b61ae42c47488a413ff92dfc7b5e16693191c20 100644 (file)
@@ -660,11 +660,22 @@ public final class Parser implements TokenId {
     /* array.initializer :
      *  '{' (( array.initializer | expression ) ',')* '}'
      */
-    private ASTree parseArrayInitializer(SymbolTable tbl)
+    private ArrayInit parseArrayInitializer(SymbolTable tbl)
         throws CompileError
     {
         lex.get();      // '{'
-        throw new CompileError("array initializer is not supported", lex);
+        ASTree expr = parseExpression(tbl);
+        ArrayInit init = new ArrayInit(expr);
+        while (lex.lookAhead() == ',') {
+            lex.get();
+            expr = parseExpression(tbl);
+            ASTList.append(init, expr);
+        }
+
+        if (lex.get() != '}')
+            throw new SyntaxError(lex);
+
+        return init;
     }
 
     /* par.expression : '(' expression ')'
@@ -1250,7 +1261,7 @@ public final class Parser implements TokenId {
      *          | primitive.type array.size [ array.initializer ]
      */
     private NewExpr parseNew(SymbolTable tbl) throws CompileError {
-        ASTree init = null;
+        ArrayInit init = null;
         int t = lex.lookAhead();
         if (isBuiltinType(t)) {
             lex.get();
index 543ecdf8ec736335933c5dfc962ca6c40b512bff..5641792288f1518f14df947edb0e281bbf670eba 100644 (file)
@@ -106,10 +106,17 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         int type = expr.getArrayType();
         ASTList size = expr.getArraySize();
         ASTList classname = expr.getClassName();
+        ASTree init = expr.getInitializer();
+        if (init != null)
+            init.accept(this);
+
         if (size.length() > 1)
             atMultiNewArray(type, classname, size);
         else {
-            size.head().accept(this);
+            ASTree sizeExpr = size.head();
+            if (sizeExpr != null)
+                sizeExpr.accept(this);
+
             exprType = type;
             arrayDim = 1;
             if (type == CLASS)
@@ -119,6 +126,16 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         }
     }
 
+    public void atArrayInit(ArrayInit init) throws CompileError {
+        ASTList list = init;
+        while (list != null) {
+            ASTree h = list.head();
+            list = list.tail();
+            if (h != null)
+                h.accept(this);
+        }
+    }
+
     protected void atMultiNewArray(int type, ASTList classname, ASTList size)
         throws CompileError
     {
diff --git a/src/main/javassist/compiler/ast/ArrayInit.java b/src/main/javassist/compiler/ast/ArrayInit.java
new file mode 100644 (file)
index 0000000..bdc35a7
--- /dev/null
@@ -0,0 +1,15 @@
+package javassist.compiler.ast;
+
+import javassist.compiler.CompileError;
+/**
+ * Array initializer such as <code>{ 1, 2, 3 }</code>.
+ */
+public class ArrayInit extends ASTList {
+    public ArrayInit(ASTree firstElement) {
+        super(firstElement);
+    }
+
+    public void accept(Visitor v) throws CompileError { v.atArrayInit(this); }
+
+    public String getTag() { return "array"; }
+}
index 1a1a3f084f4d74a7c8146cd14d9501e138ffa81c..b570ea0bb80eb7723bdf04820cb647acff767924 100644 (file)
@@ -31,7 +31,7 @@ public class NewExpr extends ASTList implements TokenId {
         arrayType = CLASS;
     }
 
-    public NewExpr(int type, ASTList arraySize, ASTree init) {
+    public NewExpr(int type, ASTList arraySize, ArrayInit init) {
         super(null, new ASTList(arraySize));
         newArray = true;
         arrayType = type;
@@ -40,7 +40,7 @@ public class NewExpr extends ASTList implements TokenId {
     }
 
     public static NewExpr makeObjectArray(ASTList className,
-                                          ASTList arraySize, ASTree init) {
+                                          ASTList arraySize, ArrayInit init) {
         NewExpr e = new NewExpr(className, arraySize);
         e.newArray = true;
         if (init != null)
@@ -61,12 +61,12 @@ public class NewExpr extends ASTList implements TokenId {
 
     public ASTList getArraySize() { return getArguments(); }
 
-    public ASTree getInitializer() {
+    public ArrayInit getInitializer() {
         ASTree t = getRight().getRight();
         if (t == null)
             return null;
         else
-            return t.getLeft();
+            return (ArrayInit)t.getLeft();
     }
 
     public void accept(Visitor v) throws CompileError { v.atNewExpr(this); }
index f8af3198b76d9ff868c0e891f8ebdf4061c3f543..5c361d8d5277afc4cd908be5b07fbae07d36403b 100644 (file)
@@ -47,4 +47,5 @@ public class Visitor {
     public void atStringL(StringL n) throws CompileError {}
     public void atIntConst(IntConst n) throws CompileError {}
     public void atDoubleConst(DoubleConst n) throws CompileError {}
+    public void atArrayInit(ArrayInit n) throws CompileError {}
 }
index 5befd301533da19ab0f3f091931f4e07d95ba5fa..31df672057b9114b1b64ce7fac9a35e41e246d56 100644 (file)
@@ -19,6 +19,7 @@
 <br><li><a href="#alter">Altering a method body</a>
 <br><li><a href="#add">Adding a new method or field</a>
 <br><li><a href="#runtime">Runtime support classes</a>
+<br><li><a href="#annotation">Annotations</a>
 <br><li><a href="#import">Import</a>
 <br><li><a href="#limit">Limitations</a>
 </ul>
@@ -1440,11 +1441,73 @@ or <code>removeMethod()</code> in <code>CtClass</code>.  A
 <code>CtConstructor</code> can be removed by <code>removeConstructor()</code>
 in <code>CtClass</code>.
 
+<p><br>
+
+<a name="annotation">
+<h3>4.4 Annotations</h3>
+
+<p><code>CtClass</code>, <code>CtMethod</code>, <code>CtField</code>
+and <code>CtConstructor</code> provides a convenient method
+<code>getAnnotations()</code> for reading annotations.
+It returns an annotation-type object.
+
+<p>For example, suppose the following annotation:
+
+<ul><pre>
+public @interface Author {
+    String name();
+    int year();
+}
+</pre></ul>
+
+<p>This annotation is used as the following:
+
+<ul><pre>
+@Author(name="Chiba", year=2005)
+public class Point {
+    int x, y;
+}
+</pre></ul>
+
+<p>Then, the value of the annotation can be obtained by
+<code>getAnnotations()</code>.
+It returns an array containing
+annotation-type objects.
+
+<ul><pre>
+CtClass cc = ClassPool.getDefault().get("Point");
+Object[] all = cc.getAnnotations();
+Author a = (Author)all[0];
+String name = a.name();
+int year = a.year();
+System.out.println("name: " + name + ", year: " + year);
+</pre></ul>
+
+<p>This code snippet should print:
+
+<ul><pre>
+name: Chiba, year: 2005
+</pre></ul>
+
+<p>
+Since the annoation of <code>Point</code> is only <code>@Author</code>,
+the length of the array <code>all</code> is one
+and <code>all[0]</code> is an <code>Author</code> object.
+The member values of the annotation can be obtained
+by calling <code>name()</code> and <code>year()</code>
+on the <code>Author</code> object.
+
+<p>To use <code>getAnnotations()</code>, annotation types
+such as <code>Author</code> must be included in the current
+class path.  <em>They must be also accessible from a
+<code>ClassPool</code> object.</em>  If the class file of an annotation
+type is not found, Javassist cannot obtain the default values
+of the members of that annotation type.
 
 <p><br>
 
 <a name="runtime">
-<h3>4.4 Runtime support classes</h3>
+<h3>4.5 Runtime support classes</h3>
 
 <p>In most cases, a class modified by Javassist does not require
 Javassist to run.  However, some kinds of bytecode generated by the
@@ -1458,7 +1521,7 @@ Javassist classes are never used at runtime of the modified classes.
 <p><br>
 
 <a name="import">
-<h3>4.5 Import</h3>
+<h3>4.6 Import</h3>
 
 <p>All the class names in source code must be fully qualified
 (they must include package names).
@@ -1494,7 +1557,7 @@ must be always a fully qualified name.
 <p><br>
 
 <a name="limit">
-<h3>4.6 Limitations</h3>
+<h3>4.7 Limitations</h3>
 
 <p>In the current implementation, the Java compiler included in Javassist
 has several limitations with respect to the language that the compiler can
@@ -1507,7 +1570,7 @@ See the <code>javassist.bytecode.annotation</code> package.
 
 <p><li>Array initializers, a comma-separated list of expressions
 enclosed by braces <code>{</code> and <code>}</code>, are not
-supported.
+available unless the array dimension is one.
 
 <p><li>Inner classes or anonymous classes are not supported.