]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-240. support for Runtime[In]VisibleTypeAnnotations
authorchibash <chiba@javassist.org>
Mon, 5 Jan 2015 16:17:34 +0000 (01:17 +0900)
committerchibash <chiba@javassist.org>
Mon, 5 Jan 2015 16:17:34 +0000 (01:17 +0900)
Readme.html
javassist.jar
src/main/javassist/bytecode/AnnotationsAttribute.java
src/main/javassist/bytecode/AttributeInfo.java
src/main/javassist/bytecode/TypeAnnotationsAttribute.java [new file with mode: 0644]
src/main/javassist/bytecode/annotation/AnnotationsWriter.java
src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java [new file with mode: 0644]
src/test/javassist/JvstTest4.java
src/test/javassist/JvstTest5.java
src/test/test5/TypeAnno.java [new file with mode: 0644]
src/test/test5/TypeAnnoA.java [new file with mode: 0644]

index 73ab11cb908ce911613b5639fdfc98dcefa53dca..1a62023741e23f2da6a185cb7a75838d45e90ab3 100644 (file)
@@ -284,7 +284,7 @@ see javassist.Dump.
 <p>-version 3.19
 <ul>
 <li>JIRA JASSIST-158, 205, 206, 207, 208, 209, 211, 212, 216, 220, 223, 224,
-        227, 230, 234, 235, 236, 237.
+        227, 230, 234, 235, 236, 237, 238, 240.
 </ul>
 </p>
 
index 58b7db8b21ecc0aaef34f8449fc34a8b5d2089f8..254637c9fd694164e2ea2b90c5ff747c0b80cc5b 100644 (file)
Binary files a/javassist.jar and b/javassist.jar differ
index f5dc581a2d8483b1662e43d32740e8630ffb0de8..38b88eaa1862ffaed744a9d7659c932bde9a344f 100644 (file)
@@ -350,15 +350,24 @@ public class AnnotationsAttribute extends AttributeInfo {
             return pos;
         }
 
+        /**
+         * {@code element_value_paris}
+         */
         final int memberValuePair(int pos) throws Exception {
             int nameIndex = ByteArray.readU16bit(info, pos);
             return memberValuePair(pos + 2, nameIndex);
         }
 
+        /**
+         * {@code element_value_paris[]}
+         */
         int memberValuePair(int pos, int nameIndex) throws Exception {
             return memberValue(pos);
         }
 
+        /**
+         * {@code element_value}
+         */
         final int memberValue(int pos) throws Exception {
             int tag = info[pos] & 0xff;
             if (tag == 'e') {
@@ -385,18 +394,33 @@ public class AnnotationsAttribute extends AttributeInfo {
             }
         }
 
+        /**
+         * {@code const_value_index}
+         */
         void constValueMember(int tag, int index) throws Exception {}
 
+        /**
+         * {@code enum_const_value}
+         */
         void enumMemberValue(int pos, int typeNameIndex, int constNameIndex)
             throws Exception {
         }
 
+        /**
+         * {@code class_info_index}
+         */
         void classMemberValue(int pos, int index) throws Exception {}
 
+        /**
+         * {@code annotation_value}
+         */
         int annotationMemberValue(int pos) throws Exception {
             return annotation(pos);
         }
 
+        /**
+         * {@code array_value}
+         */
         int arrayMemberValue(int pos, int num) throws Exception {
             for (int i = 0; i < num; ++i) {
                 pos = memberValue(pos);
@@ -470,9 +494,15 @@ public class AnnotationsAttribute extends AttributeInfo {
          *                  It can be null.
          */
         Copier(byte[] info, ConstPool src, ConstPool dest, Map map) {
+            this(info, src, dest, map, true); 
+        }
+
+        Copier(byte[] info, ConstPool src, ConstPool dest, Map map, boolean makeWriter) {
             super(info);
             output = new ByteArrayOutputStream();
-            writer = new AnnotationsWriter(output, dest);
+            if (makeWriter)
+                writer = new AnnotationsWriter(output, dest);
+
             srcPool = src;
             destPool = dest;
             classnames = map;
index 7dee78291e872a57e76ec5f526ed6963e9ea3249..5f26d5c9e86e1eff192f54d7a33d90e7f0ffb1a4 100644 (file)
@@ -74,53 +74,65 @@ public class AttributeInfo {
     {
         int name = in.readUnsignedShort();
         String nameStr = cp.getUtf8Info(name);
-        if (nameStr.charAt(0) < 'L') {
-            if (nameStr.equals(AnnotationDefaultAttribute.tag))
-                return new AnnotationDefaultAttribute(cp, name, in);
-            else if (nameStr.equals(BootstrapMethodsAttribute.tag))
-                return new BootstrapMethodsAttribute(cp, name, in);
-            else if (nameStr.equals(CodeAttribute.tag))
-                return new CodeAttribute(cp, name, in);
-            else if (nameStr.equals(ConstantAttribute.tag))
-                return new ConstantAttribute(cp, name, in);
-            else if (nameStr.equals(DeprecatedAttribute.tag))
-                return new DeprecatedAttribute(cp, name, in);
-            else if (nameStr.equals(EnclosingMethodAttribute.tag))
-                return new EnclosingMethodAttribute(cp, name, in);
-            else if (nameStr.equals(ExceptionsAttribute.tag))
-                return new ExceptionsAttribute(cp, name, in);
-            else if (nameStr.equals(InnerClassesAttribute.tag))
-                return new InnerClassesAttribute(cp, name, in);
+        char first = nameStr.charAt(0);
+        if (first < 'M') {
+            if (first < 'E') {
+                if (nameStr.equals(AnnotationDefaultAttribute.tag))
+                    return new AnnotationDefaultAttribute(cp, name, in);
+                else if (nameStr.equals(BootstrapMethodsAttribute.tag))
+                    return new BootstrapMethodsAttribute(cp, name, in);
+                else if (nameStr.equals(CodeAttribute.tag))
+                    return new CodeAttribute(cp, name, in);
+                else if (nameStr.equals(ConstantAttribute.tag))
+                    return new ConstantAttribute(cp, name, in);
+                else if (nameStr.equals(DeprecatedAttribute.tag))
+                    return new DeprecatedAttribute(cp, name, in);
+            }
+            else {
+                if (nameStr.equals(EnclosingMethodAttribute.tag))
+                    return new EnclosingMethodAttribute(cp, name, in);
+                else if (nameStr.equals(ExceptionsAttribute.tag))
+                    return new ExceptionsAttribute(cp, name, in);
+                else if (nameStr.equals(InnerClassesAttribute.tag))
+                    return new InnerClassesAttribute(cp, name, in);
+                else if (nameStr.equals(LineNumberAttribute.tag))
+                    return new LineNumberAttribute(cp, name, in);
+                else if (nameStr.equals(LocalVariableAttribute.tag))
+                    return new LocalVariableAttribute(cp, name, in);
+                else if (nameStr.equals(LocalVariableTypeAttribute.tag))
+                    return new LocalVariableTypeAttribute(cp, name, in);
+            }
         }
         else {
-            /* Note that the names of Annotations attributes begin with 'R'. 
-             */
-            if (nameStr.equals(LineNumberAttribute.tag))
-                return new LineNumberAttribute(cp, name, in);
-            else if (nameStr.equals(LocalVariableAttribute.tag))
-                return new LocalVariableAttribute(cp, name, in);
-            else if (nameStr.equals(LocalVariableTypeAttribute.tag))
-                return new LocalVariableTypeAttribute(cp, name, in);
-            else if (nameStr.equals(MethodParametersAttribute.tag))
-                return new MethodParametersAttribute(cp, name, in);
-            else if (nameStr.equals(AnnotationsAttribute.visibleTag)
-                     || nameStr.equals(AnnotationsAttribute.invisibleTag)) {
-                // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
-                return new AnnotationsAttribute(cp, name, in);
+            if (first < 'S') {
+                /* Note that the names of Annotations attributes begin with 'R'. 
+                 */
+                if (nameStr.equals(MethodParametersAttribute.tag))
+                    return new MethodParametersAttribute(cp, name, in);
+                else if (nameStr.equals(AnnotationsAttribute.visibleTag)
+                         || nameStr.equals(AnnotationsAttribute.invisibleTag)) {
+                    // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
+                    return new AnnotationsAttribute(cp, name, in);
+                }
+                else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag)
+                         || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag))
+                    return new ParameterAnnotationsAttribute(cp, name, in);
+                else if (nameStr.equals(TypeAnnotationsAttribute.visibleTag)
+                         || nameStr.equals(TypeAnnotationsAttribute.invisibleTag))
+                    return new TypeAnnotationsAttribute(cp, name, in);
+            }
+            else {
+                if (nameStr.equals(SignatureAttribute.tag))
+                    return new SignatureAttribute(cp, name, in);
+                else if (nameStr.equals(SourceFileAttribute.tag))
+                    return new SourceFileAttribute(cp, name, in);
+                else if (nameStr.equals(SyntheticAttribute.tag))
+                    return new SyntheticAttribute(cp, name, in);
+                else if (nameStr.equals(StackMap.tag))
+                    return new StackMap(cp, name, in);
+                else if (nameStr.equals(StackMapTable.tag))
+                    return new StackMapTable(cp, name, in);
             }
-            else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag)
-                || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag))
-                return new ParameterAnnotationsAttribute(cp, name, in);
-            else if (nameStr.equals(SignatureAttribute.tag))
-                return new SignatureAttribute(cp, name, in);
-            else if (nameStr.equals(SourceFileAttribute.tag))
-                return new SourceFileAttribute(cp, name, in);
-            else if (nameStr.equals(SyntheticAttribute.tag))
-                return new SyntheticAttribute(cp, name, in);
-            else if (nameStr.equals(StackMap.tag))
-                return new StackMap(cp, name, in);
-            else if (nameStr.equals(StackMapTable.tag))
-                return new StackMapTable(cp, name, in);
         }
 
         return new AttributeInfo(cp, name, in);
diff --git a/src/main/javassist/bytecode/TypeAnnotationsAttribute.java b/src/main/javassist/bytecode/TypeAnnotationsAttribute.java
new file mode 100644 (file)
index 0000000..6770620
--- /dev/null
@@ -0,0 +1,358 @@
+package javassist.bytecode;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javassist.bytecode.annotation.TypeAnnotationsWriter;
+
+/**
+ * A class representing
+ * {@code RuntimeVisibleTypeAnnotations} attribute and
+ * {@code RuntimeInvisibleTypeAnnotations} attribute.
+ */
+public class TypeAnnotationsAttribute extends AttributeInfo {
+    /**
+     * The name of the {@code RuntimeVisibleTypeAnnotations} attribute.
+     */
+    public static final String visibleTag = "RuntimeVisibleTypeAnnotations";
+
+    /**
+     * The name of the {@code RuntimeInvisibleTypeAnnotations} attribute.
+     */
+    public static final String invisibleTag = "RuntimeInvisibleTypeAnnotations";
+
+    /**
+     * Constructs a <code>Runtime(In)VisibleTypeAnnotations_attribute</code>.
+     *
+     * @param cp            constant pool
+     * @param attrname      attribute name (<code>visibleTag</code> or
+     *                      <code>invisibleTag</code>).
+     * @param info          the contents of this attribute.  It does not
+     *                      include <code>attribute_name_index</code> or
+     *                      <code>attribute_length</code>.
+     */
+    public TypeAnnotationsAttribute(ConstPool cp, String attrname, byte[] info) {
+        super(cp, attrname, info);
+    }
+
+    /**
+     * @param n     the attribute name.
+     */
+    TypeAnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
+        throws IOException
+    {
+        super(cp, n, in);
+    }
+
+    /**
+     * Returns <code>num_annotations</code>.
+     */
+    public int numAnnotations() {
+        return ByteArray.readU16bit(info, 0);
+    }
+
+    /**
+     * Copies this attribute and returns a new copy.
+     */
+    public AttributeInfo copy(ConstPool newCp, Map classnames) {
+        Copier copier = new Copier(info, constPool, newCp, classnames);
+        try {
+            copier.annotationArray();
+            return new TypeAnnotationsAttribute(newCp, getName(), copier.close());
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @param oldname       a JVM class name.
+     * @param newname       a JVM class name.
+     */
+    void renameClass(String oldname, String newname) {
+        HashMap map = new HashMap();
+        map.put(oldname, newname);
+        renameClass(map);
+    }
+
+    void renameClass(Map classnames) {
+        Renamer renamer = new Renamer(info, getConstPool(), classnames);
+        try {
+            renamer.annotationArray();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    void getRefClasses(Map classnames) { renameClass(classnames); }
+
+    /**
+     * To visit each elements of the type annotation attribute,
+     * call {@code annotationArray()}.
+     *
+     * @see #annotationArray()
+     */
+    static class TAWalker extends AnnotationsAttribute.Walker {
+        SubWalker subWalker;
+
+        TAWalker(byte[] attrInfo) {
+            super(attrInfo);
+            subWalker = new SubWalker(attrInfo);
+        }
+
+        int annotationArray(int pos, int num) throws Exception {
+            for (int i = 0; i < num; i++) {
+                int targetType = info[pos] & 0xff;
+                pos = subWalker.targetInfo(pos + 1, targetType);
+                pos = subWalker.typePath(pos);
+                pos = annotation(pos);
+            }
+
+            return pos;
+        }
+    }
+
+    static class SubWalker {
+        byte[] info;
+
+        SubWalker(byte[] attrInfo) {
+            info = attrInfo;
+        }
+
+        final int targetInfo(int pos, int type) throws Exception {
+            switch (type) {
+            case 0x00:
+            case 0x01: {
+                int index = info[pos] & 0xff;
+                typeParameterTarget(pos, type, index);
+                return pos + 1; }
+            case 0x10: {
+                int index = ByteArray.readU16bit(info, pos); 
+                supertypeTarget(pos, index);
+                return pos + 2; }
+            case 0x11:
+            case 0x12: {
+                int param = info[pos] & 0xff;
+                int bound = info[pos + 1] & 0xff;
+                typeParameterBoundTarget(pos, type, param, bound);
+                return pos + 2; }
+            case 0x13:
+            case 0x14:
+            case 0x15:
+                emptyTarget(pos, type);
+                return pos;
+            case 0x16: {
+                int index = info[pos] & 0xff;
+                formalParameterTarget(pos, index);
+                return pos + 1; }
+            case 0x17: {
+                int index = ByteArray.readU16bit(info, pos); 
+                throwsTarget(pos, index);
+                return pos + 2; }
+            case 0x40:
+            case 0x41: {
+                int len = ByteArray.readU16bit(info, pos); 
+                return localvarTarget(pos + 2, type, len); }
+            case 0x42: {
+                int index = ByteArray.readU16bit(info, pos); 
+                catchTarget(pos, index);
+                return pos + 2; }
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46: {
+                int offset = ByteArray.readU16bit(info, pos); 
+                offsetTarget(pos, type, offset);
+                return pos + 2; }
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4a:
+            case 0x4b: {
+                int offset = ByteArray.readU16bit(info, pos);
+                int index = info[pos + 2] & 0xff;
+                typeArgumentTarget(pos, type, offset, index);
+                return pos + 3; }
+            default:
+                throw new RuntimeException("invalid target type: " + type);
+            }
+        }
+
+        void typeParameterTarget(int pos, int targetType, int typeParameterIndex)
+            throws Exception {}
+
+        void supertypeTarget(int pos, int superTypeIndex) throws Exception {}
+
+        void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex,
+                                      int boundIndex) throws Exception {}
+
+        void emptyTarget(int pos, int targetType) throws Exception {}
+
+        void formalParameterTarget(int pos, int formalParameterIndex) throws Exception {}
+
+        void throwsTarget(int pos, int throwsTypeIndex) throws Exception {}
+
+        int localvarTarget(int pos, int targetType, int tableLength) throws Exception {
+            for (int i = 0; i < tableLength; i++) {
+                int start = ByteArray.readU16bit(info, pos);
+                int length = ByteArray.readU16bit(info, pos + 2);
+                int index = ByteArray.readU16bit(info, pos + 4);
+                localvarTarget(pos, targetType, start, length, index);
+                pos += 6;
+            }
+
+            return pos;
+        }
+
+        void localvarTarget(int pos, int targetType, int startPc, int length, int index)
+            throws Exception {}
+
+        void catchTarget(int pos, int exceptionTableIndex) throws Exception {}
+
+        void offsetTarget(int pos, int targetType, int offset) throws Exception {}
+
+        void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex)
+            throws Exception {}
+
+        final int typePath(int pos) throws Exception {
+            int len = info[pos++] & 0xff;
+            return typePath(pos, len);
+        }
+
+        int typePath(int pos, int pathLength) throws Exception {
+            for (int i = 0; i < pathLength; i++) {
+                int kind = info[pos] & 0xff;
+                int index = info[pos + 1] & 0xff;
+                typePath(pos, kind, index);
+                pos += 2;
+            }
+
+            return pos;
+        }
+
+        void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception {}
+    }
+
+    static class Renamer extends AnnotationsAttribute.Renamer {
+        SubWalker sub;
+
+        Renamer(byte[] attrInfo, ConstPool cp, Map map) {
+            super(attrInfo, cp, map);
+            sub = new SubWalker(attrInfo);
+        }
+
+        int annotationArray(int pos, int num) throws Exception {
+            for (int i = 0; i < num; i++) {
+                int targetType = info[pos] & 0xff;
+                pos = sub.targetInfo(pos + 1, targetType);
+                pos = sub.typePath(pos);
+                pos = annotation(pos);
+            }
+
+            return pos;
+        }
+    }
+
+    static class Copier extends AnnotationsAttribute.Copier {
+        SubCopier sub;
+
+        Copier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map) {
+            super(attrInfo, src, dest, map, false);
+            TypeAnnotationsWriter w = new TypeAnnotationsWriter(output, dest);
+            writer = w;
+            sub = new SubCopier(attrInfo, src, dest, map, w);
+        }
+
+        int annotationArray(int pos, int num) throws Exception {
+            writer.numAnnotations(num);
+            for (int i = 0; i < num; i++) {
+                int targetType = info[pos] & 0xff;
+                pos = sub.targetInfo(pos + 1, targetType);
+                pos = sub.typePath(pos);
+                pos = annotation(pos);
+            }
+
+            return pos;
+        }
+    }
+
+    static class SubCopier extends SubWalker {
+        ConstPool srcPool, destPool;
+        Map classnames;
+        TypeAnnotationsWriter writer;
+
+        SubCopier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map,
+                TypeAnnotationsWriter w)
+        {
+            super(attrInfo);
+            srcPool = src;
+            destPool = dest;
+            classnames = map;
+            writer = w;
+        }
+
+        void typeParameterTarget(int pos, int targetType, int typeParameterIndex)
+            throws Exception
+        {
+            writer.typeParameterTarget(targetType, typeParameterIndex);            
+        }
+
+        void supertypeTarget(int pos, int superTypeIndex) throws Exception {
+            writer.supertypeTarget(superTypeIndex);
+        }
+
+        void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex,
+                                      int boundIndex)
+            throws Exception
+        {
+            writer.typeParameterBoundTarget(targetType, typeParameterIndex, boundIndex);
+        }
+
+        void emptyTarget(int pos, int targetType) throws Exception {
+            writer.emptyTarget(targetType);
+        }
+
+        void formalParameterTarget(int pos, int formalParameterIndex) throws Exception {
+            writer.formalParameterTarget(formalParameterIndex);
+        }
+
+        void throwsTarget(int pos, int throwsTypeIndex) throws Exception {
+            writer.throwsTarget(throwsTypeIndex);
+        }
+
+        int localvarTarget(int pos, int targetType, int tableLength) throws Exception {
+            writer.localVarTarget(targetType, tableLength);
+            return super.localvarTarget(pos, targetType, tableLength);
+        }
+
+        void localvarTarget(int pos, int targetType, int startPc, int length, int index)
+            throws Exception
+        {
+            writer.localVarTargetTable(startPc, length, index);
+        }
+
+        void catchTarget(int pos, int exceptionTableIndex) throws Exception {
+            writer.catchTarget(exceptionTableIndex);
+        }
+
+        void offsetTarget(int pos, int targetType, int offset) throws Exception {
+            writer.offsetTarget(targetType, offset);
+        }
+
+        void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex)
+            throws Exception
+        {
+            writer.typeArgumentTarget(targetType, offset, typeArgumentIndex);
+        }
+
+        int typePath(int pos, int pathLength) throws Exception {
+            writer.typePath(pathLength);
+            return super.typePath(pos, pathLength);
+        }
+
+        void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception {
+            writer.typePathPath(typePathKind, typeArgumentIndex);
+        }
+    }
+}
index 5a510a4c3d3edc70d8f4eac9519d147da8ad8f7b..b366acb800479b905ab20d74331df129267dca35 100644 (file)
@@ -35,9 +35,9 @@ import javassist.bytecode.ConstPool;
  *
  * writer.numAnnotations(1);
  * writer.annotation("Author", 2);
- * writer.memberValuePair("name");
+ * writer.memberValuePair("name");      // element_value_pair
  * writer.constValueIndex("chiba");
- * writer.memberValuePair("address");
+ * writer.memberValuePair("address");   // element_value_pair
  * writer.constValueIndex("tokyo");
  *
  * writer.close();
@@ -58,7 +58,7 @@ import javassist.bytecode.ConstPool;
  * @see javassist.bytecode.ParameterAnnotationsAttribute
  */
 public class AnnotationsWriter {
-    private OutputStream output;
+    protected OutputStream output;
     private ConstPool pool;
 
     /**
@@ -113,7 +113,7 @@ public class AnnotationsWriter {
      * calls to <code>memberValuePair()</code>.
      *
      * @param type                  the annotation interface name.
-     * @param numMemberValuePairs   <code>num_member_value_pairs</code>
+     * @param numMemberValuePairs   <code>num_element_value_pairs</code>
      *                              in <code>annotation</code>.
      */
     public void annotation(String type, int numMemberValuePairs)
@@ -128,7 +128,7 @@ public class AnnotationsWriter {
      * calls to <code>memberValuePair()</code>.
      *
      * @param typeIndex  <code>type_index</code> in <code>annotation</code>.
-     * @param numMemberValuePairs   <code>num_member_value_pairs</code>
+     * @param numMemberValuePairs   <code>num_element_value_pairs</code>
      *                              in <code>annotation</code>.
      */
     public void annotation(int typeIndex, int numMemberValuePairs)
@@ -139,27 +139,27 @@ public class AnnotationsWriter {
     }
 
     /**
-     * Writes an element of a <code>member_value_pairs</code> array
+     * Writes an element of a <code>element_value_pairs</code> array
      * in <code>annotation</code>.
      * This method must be followed by a
      * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
      * etc.
      *
-     * @param memberName        the name of the annotation type member.
+     * @param memberName        the element name.
      */
     public void memberValuePair(String memberName) throws IOException {
         memberValuePair(pool.addUtf8Info(memberName));
     }
 
     /**
-     * Writes an element of a <code>member_value_pairs</code> array
+     * Writes an element of a <code>element_value_pairs</code> array
      * in <code>annotation</code>.
      * This method must be followed by a
      * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
      * etc.
      *
-     * @param memberNameIndex   <code>member_name_index</code>
-     *                          in <code>member_value_pairs</code> array.
+     * @param memberNameIndex   <code>element_name_index</code>
+     *                          in <code>element_value_pairs</code> array.
      */
     public void memberValuePair(int memberNameIndex) throws IOException {
         write16bit(memberNameIndex);
@@ -167,7 +167,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -177,7 +177,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -187,7 +187,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -197,7 +197,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -207,7 +207,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -217,7 +217,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -227,7 +227,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -237,7 +237,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -247,7 +247,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param value     the constant value.
      */
@@ -257,11 +257,11 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>const_value_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
-     * @param tag       <code>tag</code> in <code>member_value</code>.
+     * @param tag       <code>tag</code> in <code>element_value</code>.
      * @param index     <code>const_value_index</code>
-     *                              in <code>member_value</code>.
+     *                              in <code>element_value</code>.
      */
     public void constValueIndex(int tag, int index)
         throws IOException
@@ -272,7 +272,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>enum_const_value</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param typeName      the type name of the enum constant.
      * @param constName     the simple name of the enum constant.
@@ -286,12 +286,12 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>enum_const_value</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param typeNameIndex       <code>type_name_index</code>
-     *                              in <code>member_value</code>.
+     *                              in <code>element_value</code>.
      * @param constNameIndex     <code>const_name_index</code>
-     *                              in <code>member_value</code>.
+     *                              in <code>element_value</code>.
      */
     public void enumConstValue(int typeNameIndex, int constNameIndex)
         throws IOException
@@ -303,7 +303,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>class_info_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param name      the class name.
      */
@@ -313,7 +313,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>class_info_index</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      *
      * @param index       <code>class_info_index</code>
      */
@@ -324,7 +324,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>annotation_value</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      * This method must be followed by a call to <code>annotation()</code>.
      */
     public void annotationValue() throws IOException {
@@ -333,7 +333,7 @@ public class AnnotationsWriter {
 
     /**
      * Writes <code>tag</code> and <code>array_value</code> 
-     * in <code>member_value</code>.
+     * in <code>element_value</code>.
      * This method must be followed by <code>numValues</code> calls
      * to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
      * etc.
@@ -346,7 +346,7 @@ public class AnnotationsWriter {
         write16bit(numValues);
     }
 
-    private void write16bit(int value) throws IOException {
+    protected void write16bit(int value) throws IOException {
         byte[] buf = new byte[2];
         ByteArray.write16bit(value, buf, 0);
         output.write(buf);
diff --git a/src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java b/src/main/javassist/bytecode/annotation/TypeAnnotationsWriter.java
new file mode 100644 (file)
index 0000000..a1932e0
--- /dev/null
@@ -0,0 +1,172 @@
+package javassist.bytecode.annotation;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javassist.bytecode.ConstPool;
+
+/**
+ * A convenience class for constructing a
+ * {@code ..TypeAnnotations_attribute}.
+ * See the source code of the {@link javassist.bytecode.TypeAnnotationsAttribute} class.
+ */
+public class TypeAnnotationsWriter extends AnnotationsWriter {
+    /**
+     * Constructs with the given output stream.
+     *
+     * @param os    the output stream.
+     * @param cp    the constant pool.
+     */
+    public TypeAnnotationsWriter(OutputStream os, ConstPool cp) {
+        super(os, cp);
+    }
+
+    /**
+     * Writes {@code num_annotations} in
+     * {@code Runtime(In)VisibleTypeAnnotations_attribute}.
+     * It must be followed by {@code num} instances of {@code type_annotation}.
+     */
+    public void numAnnotations(int num) throws IOException {
+        super.numAnnotations(num);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code type_parameter_target}
+     * of {@code target_info} union.
+     */
+    public void typeParameterTarget(int targetType, int typeParameterIndex)
+        throws IOException
+    {
+        output.write(targetType);
+        output.write(typeParameterIndex);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code supertype_target}
+     * of {@code target_info} union.
+     */
+    public void supertypeTarget(int supertypeIndex)
+        throws IOException
+    {
+        output.write(0x10);
+        write16bit(supertypeIndex);
+    }    
+
+    /**
+     * Writes {@code target_type} and {@code type_parameter_bound_target}
+     * of {@code target_info} union.
+     */
+    public void typeParameterBoundTarget(int targetType, int typeParameterIndex, int boundIndex)
+        throws IOException
+    {
+        output.write(targetType);
+        output.write(typeParameterIndex);
+        output.write(boundIndex);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code empty_target}
+     * of {@code target_info} union.
+     */
+    public void emptyTarget(int targetType) throws IOException {
+        output.write(targetType);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code type_parameter_target}
+     * of {@code target_info} union.
+     */
+    public void formalParameterTarget(int formalParameterIndex)
+        throws IOException
+    {
+        output.write(0x16);
+        output.write(formalParameterIndex);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code throws_target}
+     * of {@code target_info} union.
+     */
+    public void throwsTarget(int throwsTypeIndex)
+        throws IOException
+    {
+        output.write(0x17);
+        write16bit(throwsTypeIndex);
+    } 
+
+    /**
+     * Writes {@code target_type} and {@code localvar_target}
+     * of {@code target_info} union.
+     * It must be followed by {@code tableLength} calls
+     * to {@code localVarTargetTable}.
+     */
+    public void localVarTarget(int targetType, int tableLength)
+        throws IOException
+    {
+        output.write(targetType);
+        write16bit(tableLength);
+    }
+
+    /**
+     * Writes an element of {@code table[]} of {@code localvar_target}
+     * of {@code target_info} union.
+     */
+    public void localVarTargetTable(int startPc, int length, int index)
+        throws IOException
+    {
+        write16bit(startPc);
+        write16bit(length);
+        write16bit(index);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code catch_target}
+     * of {@code target_info} union.
+     */
+    public void catchTarget(int exceptionTableIndex)
+        throws IOException
+    {
+        output.write(0x42);
+        write16bit(exceptionTableIndex);
+    } 
+
+    /**
+     * Writes {@code target_type} and {@code offset_target}
+     * of {@code target_info} union.
+     */
+    public void offsetTarget(int targetType, int offset)
+        throws IOException
+    {
+        output.write(targetType);
+        write16bit(offset);
+    }
+
+    /**
+     * Writes {@code target_type} and {@code type_argument_target}
+     * of {@code target_info} union.
+     */
+    public void typeArgumentTarget(int targetType, int offset, int type_argument_index)
+        throws IOException
+    {
+        output.write(targetType);
+        write16bit(offset);
+        output.write(type_argument_index);
+    }
+
+    /**
+     * Writes {@code path_length} of {@code type_path}.
+     */
+    public void typePath(int pathLength) throws IOException {
+        output.write(pathLength);
+    }
+
+    /**
+     * Writes an element of {@code path[]} of {@code type_path}. 
+     */
+    public void typePathPath(int typePathKind, int typeArgumentIndex)
+        throws IOException
+    {
+        output.write(typePathKind);
+        output.write(typeArgumentIndex);
+    }
+}
index d5616056b9ddd1f33524ba6518fbb02d86921d73..c39f6700b7d857e671d5ac9057c28746500e9914 100644 (file)
@@ -606,10 +606,10 @@ public class JvstTest4 extends JvstTestRoot {
         assertEquals(packageName, obj.getClass().getPackage().getName());
     }
 
-    public static final String BASE_PATH="../";
-    public static final String JAVASSIST_JAR=BASE_PATH+"javassist.jar";
-    public static final String CLASSES_FOLDER=BASE_PATH+"build/classes";
-    public static final String TEST_CLASSES_FOLDER=BASE_PATH+"build/test-classes";
+    public static final String BASE_PATH = "../";
+    public static final String JAVASSIST_JAR = BASE_PATH + "javassist.jar";
+    public static final String CLASSES_FOLDER = BASE_PATH + "build/classes";
+    public static final String TEST_CLASSES_FOLDER = BASE_PATH + "build/test-classes";
 
     public static class Inner1 {
         public static int get() {
@@ -661,8 +661,8 @@ public class JvstTest4 extends JvstTestRoot {
         long t2 = endTime2 - endTime;
         long t3 = endTime3 - endTime2;
         System.out.println("JIRA150: " + t1 + ", " + t2 + ", " + t3);
-        assertTrue("performance test (the next try may succeed): " + t1 + "/ 5 < " + t2,
-                   t2 < t1 * 5);
+        assertTrue("performance test (the next try may succeed): " + t1 + "/ 6 < " + t2,
+                   t2 < t1 * 6);
         assertTrue("", t3 < t1 * 3);
     }
 
@@ -691,15 +691,17 @@ public class JvstTest4 extends JvstTestRoot {
         }
 
         // try to run garbage collection.
+        int[][] mem = new int[100][];
         int[] large;
         for (int i = 0; i < 100; i++) {
             large = new int[1000000];
-            large[large.length - 2] = 9;
+            large[large.length - 2] = 9 + i;
+            mem[i] = large;
         }
         System.gc();
         System.gc();
         int size = javassist.compiler.MemberResolver.getInvalidMapSize();
-        System.out.println("JIRA150b " + size);
+        System.out.println("JIRA150b " + size + " " + mem[mem.length - 1][mem[0].length - 2]);
         assertTrue("JIRA150b size: " + origSize + " " + size, size < origSize + N);
     }
 
index 32cebbe281499080a8e7e84cd0537e700637e922..becd5c59d3697d1ff192fbff80c04e613d40da08 100644 (file)
@@ -1,5 +1,8 @@
 package javassist;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.TypeVariable;
+
 public class JvstTest5 extends JvstTestRoot {
     public JvstTest5(String name) {
         super(name);
@@ -31,4 +34,14 @@ public class JvstTest5 extends JvstTestRoot {
         assertEquals(10, invoke(obj, "run2"));
         assertEquals(10, invoke(obj, "run3"));
     }
+
+    public void testTypeAnno() throws Exception {
+        CtClass cc = sloader.get("test5.TypeAnno");
+        cc.getClassFile().compact();
+        cc.writeFile();
+        Object obj = make(cc.getName());
+        TypeVariable<?> t = obj.getClass().getTypeParameters()[0];
+        Annotation[] annos = t.getAnnotations();
+        assertEquals("@test5.TypeAnnoA()", annos[0].toString());
+    }
 }
diff --git a/src/test/test5/TypeAnno.java b/src/test/test5/TypeAnno.java
new file mode 100644 (file)
index 0000000..a24d400
--- /dev/null
@@ -0,0 +1,30 @@
+package test5;
+
+import java.util.ArrayList;
+
+class TypeAnnoSuper {}
+interface TypeAnnoI {}
+
+@TypeAnnoA
+public class TypeAnno<@TypeAnnoA TT extends @TypeAnnoA String> extends @TypeAnnoA TypeAnnoSuper implements @TypeAnnoA TypeAnnoI {
+    public @TypeAnnoA String foo(@TypeAnnoA int i) throws @TypeAnnoA Exception {
+        @TypeAnnoA String s = new @TypeAnnoA String("bar ");
+        Object t = s;
+        String ss = (@TypeAnnoA String)t;
+        ArrayList<@TypeAnnoA String> list = new ArrayList<@TypeAnnoA String>();
+        if (list instanceof  /* @TypeAnnoA */ java.util.List)
+            System.out.println("ok");
+
+        try {
+            list.add(ss);
+        } catch (@TypeAnnoA RuntimeException e) {}
+        return "foo" + list.get(0) + i;
+    }
+
+    @TypeAnnoA double dvalue;
+    @TypeAnnoA int ivalue @TypeAnnoA [] @TypeAnnoA [] @TypeAnnoA [];
+
+    <@TypeAnnoA T extends @TypeAnnoA String> T bar(T t) { return t; }
+
+    @TypeAnnoA TT getNull() { return null; }
+}
diff --git a/src/test/test5/TypeAnnoA.java b/src/test/test5/TypeAnnoA.java
new file mode 100644 (file)
index 0000000..7526778
--- /dev/null
@@ -0,0 +1,10 @@
+package test5;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE_USE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TypeAnnoA {}