aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Readme.html6
-rw-r--r--build.xml2
-rw-r--r--src/main/javassist/CtBehavior.java16
-rw-r--r--src/main/javassist/CtClass.java25
-rw-r--r--src/main/javassist/CtClassType.java45
-rw-r--r--src/main/javassist/CtField.java16
-rw-r--r--src/main/javassist/CtMember.java12
-rw-r--r--src/main/javassist/bytecode/annotation/Annotation.java19
-rw-r--r--src/main/javassist/bytecode/annotation/AnnotationImpl.java91
-rw-r--r--src/main/javassist/bytecode/annotation/AnnotationMemberValue.java14
-rw-r--r--src/main/javassist/bytecode/annotation/ArrayMemberValue.java22
-rw-r--r--src/main/javassist/bytecode/annotation/BooleanMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/ByteMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/CharMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/ClassMemberValue.java19
-rw-r--r--src/main/javassist/bytecode/annotation/DoubleMemberValue.java11
-rw-r--r--src/main/javassist/bytecode/annotation/EnumMemberValue.java20
-rw-r--r--src/main/javassist/bytecode/annotation/FloatMemberValue.java11
-rw-r--r--src/main/javassist/bytecode/annotation/IntegerMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/LongMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/MemberValue.java16
-rw-r--r--src/main/javassist/bytecode/annotation/ShortMemberValue.java9
-rw-r--r--src/main/javassist/bytecode/annotation/StringMemberValue.java9
-rw-r--r--src/main/javassist/compiler/CodeGen.java13
-rw-r--r--src/main/javassist/compiler/MemberCodeGen.java70
-rw-r--r--src/main/javassist/compiler/Parser.java17
-rw-r--r--src/main/javassist/compiler/TypeChecker.java19
-rw-r--r--src/main/javassist/compiler/ast/ArrayInit.java15
-rw-r--r--src/main/javassist/compiler/ast/NewExpr.java8
-rw-r--r--src/main/javassist/compiler/ast/Visitor.java1
-rw-r--r--tutorial/tutorial2.html71
31 files changed, 586 insertions, 36 deletions
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.
<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>
diff --git a/build.xml b/build.xml
index 9663a986..3c9a6261 100644
--- 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"/>
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
@@ -81,6 +81,22 @@ public abstract class CtBehavior extends CtMember {
}
/**
+ * 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.
*/
public CtClass[] getParameterTypes() throws NotFoundException {
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 <code>CtClass</code> represents a class.
@@ -419,6 +427,19 @@ public abstract class CtClass {
}
/**
+ * 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.
*
* @param mod modifiers encoded by
@@ -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)
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
@@ -218,6 +218,22 @@ public class CtField extends CtMember {
}
/**
+ * 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.
*/
public CtClass getType() throws NotFoundException {
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
@@ -110,6 +110,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.
*
* <p>As for constructor names, see <code>getName()</code>
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)
@@ -267,6 +268,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.
*
* @param writer the output.
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 <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.
*
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 <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.
*/
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 <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.
*/
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;
@@ -35,6 +36,21 @@ public abstract class MemberValue {
}
/**
+ * 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.
*/
public abstract void accept(MemberValueVisitor 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 <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"; }
+}
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 @@
<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.