From 9366fe08625ceb75692b53cdb9be19dff2ad56c6 Mon Sep 17 00:00:00 2001 From: chiba Date: Thu, 25 Aug 2005 05:08:05 +0000 Subject: [PATCH] Array initializer supports and better annotation supports. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@196 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 6 +- build.xml | 2 +- src/main/javassist/CtBehavior.java | 16 ++++ src/main/javassist/CtClass.java | 25 ++++- src/main/javassist/CtClassType.java | 45 +++++++++ src/main/javassist/CtField.java | 16 ++++ src/main/javassist/CtMember.java | 12 +++ .../bytecode/annotation/Annotation.java | 19 +++- .../bytecode/annotation/AnnotationImpl.java | 91 +++++++++++++++++++ .../annotation/AnnotationMemberValue.java | 14 +++ .../bytecode/annotation/ArrayMemberValue.java | 22 +++++ .../annotation/BooleanMemberValue.java | 9 ++ .../bytecode/annotation/ByteMemberValue.java | 9 ++ .../bytecode/annotation/CharMemberValue.java | 9 ++ .../bytecode/annotation/ClassMemberValue.java | 19 +++- .../annotation/DoubleMemberValue.java | 11 ++- .../bytecode/annotation/EnumMemberValue.java | 20 ++++ .../bytecode/annotation/FloatMemberValue.java | 11 ++- .../annotation/IntegerMemberValue.java | 9 ++ .../bytecode/annotation/LongMemberValue.java | 9 ++ .../bytecode/annotation/MemberValue.java | 16 ++++ .../bytecode/annotation/ShortMemberValue.java | 9 ++ .../annotation/StringMemberValue.java | 9 ++ src/main/javassist/compiler/CodeGen.java | 13 ++- .../javassist/compiler/MemberCodeGen.java | 70 +++++++++++--- src/main/javassist/compiler/Parser.java | 17 +++- src/main/javassist/compiler/TypeChecker.java | 19 +++- .../javassist/compiler/ast/ArrayInit.java | 15 +++ src/main/javassist/compiler/ast/NewExpr.java | 8 +- src/main/javassist/compiler/ast/Visitor.java | 1 + tutorial/tutorial2.html | 71 ++++++++++++++- 31 files changed, 586 insertions(+), 36 deletions(-) create mode 100644 src/main/javassist/bytecode/annotation/AnnotationImpl.java create mode 100644 src/main/javassist/compiler/ast/ArrayInit.java diff --git a/Readme.html b/Readme.html index 7227b9ba..9ea78d47 100644 --- a/Readme.html +++ b/Readme.html @@ -282,10 +282,14 @@ see javassist.Dump.

Changes

-

- version 3.1 +

- version 3.1 RC1

diff --git a/build.xml b/build.xml index 9663a986..3c9a6261 100644 --- a/build.xml +++ b/build.xml @@ -6,7 +6,7 @@ - + diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index 791457c4..a8baaf8c 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -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. */ diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index b2d6ff10..a96701b2 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -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 CtClass 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 @Author is associated + * with this class, the returned array contains an Author + * object. The member values can be obtained by calling methods on + * the Author 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 { *

This is a convenient method mainly for adding * a user-defined attribute. For dealing with attributes, see the * javassist.bytecode package. For example, the following - * expression adds an attribute of a class file. + * expression adds an attribute info to a class file. * *

          * getClassFile().addAttribute(info)
    diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
    index b400d8b1..d5989406 100644
    --- a/src/main/javassist/CtClassType.java
    +++ b/src/main/javassist/CtClassType.java
    @@ -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;
    diff --git a/src/main/javassist/CtField.java b/src/main/javassist/CtField.java
    index 710f8c50..f4f2986a 100644
    --- a/src/main/javassist/CtField.java
    +++ b/src/main/javassist/CtField.java
    @@ -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.
          */
    diff --git a/src/main/javassist/CtMember.java b/src/main/javassist/CtMember.java
    index ee8aadbc..d6bd14f1 100644
    --- a/src/main/javassist/CtMember.java
    +++ b/src/main/javassist/CtMember.java
    @@ -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 @Author is associated
    +     * with this member, the returned array contains an Author
    +     * object.  The member values can be obtained by calling methods on
    +     * the Author object.
    +     *
    +     * @return an array of annotation-type objects.
    +     * @see CtClass#getAnnotations()
    +     */
    +    public abstract Object[] getAnnotations() throws ClassNotFoundException;
    +
         /**
          * Obtains the name of the member.
          *
    diff --git a/src/main/javassist/bytecode/annotation/Annotation.java b/src/main/javassist/bytecode/annotation/Annotation.java
    index f4f8ac61..9971fada 100644
    --- a/src/main/javassist/bytecode/annotation/Annotation.java
    +++ b/src/main/javassist/bytecode/annotation/Annotation.java
    @@ -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 @Author,
    +     * this method returns an Author 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
    index 00000000..f81b7b46
    --- /dev/null
    +++ b/src/main/javassist/bytecode/annotation/AnnotationImpl.java
    @@ -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 + "()");
    +    }
    +}
    diff --git a/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java b/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java
    index 92b3e2d4..73da1637 100644
    --- a/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/AnnotationMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/ArrayMemberValue.java b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java
    index 351ffc56..dd586bb3 100644
    --- a/src/main/javassist/bytecode/annotation/ArrayMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java
    @@ -14,8 +14,10 @@
      */
     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.
          *
    diff --git a/src/main/javassist/bytecode/annotation/BooleanMemberValue.java b/src/main/javassist/bytecode/annotation/BooleanMemberValue.java
    index 4f6507e5..7df117d7 100644
    --- a/src/main/javassist/bytecode/annotation/BooleanMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/BooleanMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/ByteMemberValue.java b/src/main/javassist/bytecode/annotation/ByteMemberValue.java
    index 043f1d21..3b892010 100644
    --- a/src/main/javassist/bytecode/annotation/ByteMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/ByteMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/CharMemberValue.java b/src/main/javassist/bytecode/annotation/CharMemberValue.java
    index c01b7b78..8d056d8b 100644
    --- a/src/main/javassist/bytecode/annotation/CharMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/CharMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/ClassMemberValue.java b/src/main/javassist/bytecode/annotation/ClassMemberValue.java
    index 90da2c41..f5f2fe67 100644
    --- a/src/main/javassist/bytecode/annotation/ClassMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/ClassMemberValue.java
    @@ -15,12 +15,13 @@
     
     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 Bill Burke
      * @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.
          *
    diff --git a/src/main/javassist/bytecode/annotation/DoubleMemberValue.java b/src/main/javassist/bytecode/annotation/DoubleMemberValue.java
    index 131e35f8..7c987875 100644
    --- a/src/main/javassist/bytecode/annotation/DoubleMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/DoubleMemberValue.java
    @@ -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 Bill Burke
      * @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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/EnumMemberValue.java b/src/main/javassist/bytecode/annotation/EnumMemberValue.java
    index cf6263a7..77e07c27 100644
    --- a/src/main/javassist/bytecode/annotation/EnumMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/EnumMemberValue.java
    @@ -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.
          *
    diff --git a/src/main/javassist/bytecode/annotation/FloatMemberValue.java b/src/main/javassist/bytecode/annotation/FloatMemberValue.java
    index 87e12ab7..622a9420 100644
    --- a/src/main/javassist/bytecode/annotation/FloatMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/FloatMemberValue.java
    @@ -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 Bill Burke
      * @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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/IntegerMemberValue.java b/src/main/javassist/bytecode/annotation/IntegerMemberValue.java
    index e8846276..949f3752 100644
    --- a/src/main/javassist/bytecode/annotation/IntegerMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/IntegerMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/LongMemberValue.java b/src/main/javassist/bytecode/annotation/LongMemberValue.java
    index 4842792f..a0dd13ad 100644
    --- a/src/main/javassist/bytecode/annotation/LongMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/LongMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/MemberValue.java b/src/main/javassist/bytecode/annotation/MemberValue.java
    index 84d0eb38..8ee6ce9a 100644
    --- a/src/main/javassist/bytecode/annotation/MemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/MemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/ShortMemberValue.java b/src/main/javassist/bytecode/annotation/ShortMemberValue.java
    index fc0a1702..7d38f4b4 100644
    --- a/src/main/javassist/bytecode/annotation/ShortMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/ShortMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/bytecode/annotation/StringMemberValue.java b/src/main/javassist/bytecode/annotation/StringMemberValue.java
    index 4a32e433..80cb5e3d 100644
    --- a/src/main/javassist/bytecode/annotation/StringMemberValue.java
    +++ b/src/main/javassist/bytecode/annotation/StringMemberValue.java
    @@ -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.
          */
    diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java
    index 9b401804..6739c17a 100644
    --- a/src/main/javassist/compiler/CodeGen.java
    +++ b/src/main/javassist/compiler/CodeGen.java
    @@ -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
         {
    diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java
    index 88023202..ae586d68 100644
    --- a/src/main/javassist/compiler/MemberCodeGen.java
    +++ b/src/main/javassist/compiler/MemberCodeGen.java
    @@ -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
         {
    diff --git a/src/main/javassist/compiler/Parser.java b/src/main/javassist/compiler/Parser.java
    index e1a0d5b2..5b61ae42 100644
    --- a/src/main/javassist/compiler/Parser.java
    +++ b/src/main/javassist/compiler/Parser.java
    @@ -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();
    diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java
    index 543ecdf8..56417922 100644
    --- a/src/main/javassist/compiler/TypeChecker.java
    +++ b/src/main/javassist/compiler/TypeChecker.java
    @@ -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
    index 00000000..bdc35a75
    --- /dev/null
    +++ b/src/main/javassist/compiler/ast/ArrayInit.java
    @@ -0,0 +1,15 @@
    +package javassist.compiler.ast;
    +
    +import javassist.compiler.CompileError;
    +/**
    + * Array initializer such as { 1, 2, 3 }.
    + */
    +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"; }
    +}
    diff --git a/src/main/javassist/compiler/ast/NewExpr.java b/src/main/javassist/compiler/ast/NewExpr.java
    index 1a1a3f08..b570ea0b 100644
    --- a/src/main/javassist/compiler/ast/NewExpr.java
    +++ b/src/main/javassist/compiler/ast/NewExpr.java
    @@ -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); }
    diff --git a/src/main/javassist/compiler/ast/Visitor.java b/src/main/javassist/compiler/ast/Visitor.java
    index f8af3198..5c361d8d 100644
    --- a/src/main/javassist/compiler/ast/Visitor.java
    +++ b/src/main/javassist/compiler/ast/Visitor.java
    @@ -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 {}
     }
    diff --git a/tutorial/tutorial2.html b/tutorial/tutorial2.html
    index 5befd301..31df6720 100644
    --- a/tutorial/tutorial2.html
    +++ b/tutorial/tutorial2.html
    @@ -19,6 +19,7 @@
     
  • Altering a method body
  • Adding a new method or field
  • Runtime support classes +
  • Annotations
  • Import
  • Limitations
@@ -1440,11 +1441,73 @@ or removeMethod() in CtClass. A CtConstructor can be removed by removeConstructor() in CtClass. +


+ + +

4.4 Annotations

+ +

CtClass, CtMethod, CtField +and CtConstructor provides a convenient method +getAnnotations() for reading annotations. +It returns an annotation-type object. + +

For example, suppose the following annotation: + +

    +public @interface Author {
    +    String name();
    +    int year();
    +}
    +
+ +

This annotation is used as the following: + +

    +@Author(name="Chiba", year=2005)
    +public class Point {
    +    int x, y;
    +}
    +
+ +

Then, the value of the annotation can be obtained by +getAnnotations(). +It returns an array containing +annotation-type objects. + +

    +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);
    +
+ +

This code snippet should print: + +

    +name: Chiba, year: 2005
    +
+ +

+Since the annoation of Point is only @Author, +the length of the array all is one +and all[0] is an Author object. +The member values of the annotation can be obtained +by calling name() and year() +on the Author object. + +

To use getAnnotations(), annotation types +such as Author must be included in the current +class path. They must be also accessible from a +ClassPool object. If the class file of an annotation +type is not found, Javassist cannot obtain the default values +of the members of that annotation type.


-

4.4 Runtime support classes

+

4.5 Runtime support classes

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.


-

4.5 Import

+

4.6 Import

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.


-

4.6 Limitations

+

4.7 Limitations

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 javassist.bytecode.annotation package.

  • Array initializers, a comma-separated list of expressions enclosed by braces { and }, are not -supported. +available unless the array dimension is one.

  • Inner classes or anonymous classes are not supported. -- 2.39.5