All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.toplink.libraries.asm.attrs.Annotation Maven / Gradle / Ivy

The newest version!
/**
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000,2002,2003 INRIA, France Telecom 
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package oracle.toplink.libraries.asm.attrs;

import java.util.ArrayList;
import java.util.List;

import oracle.toplink.libraries.asm.ByteVector;
import oracle.toplink.libraries.asm.ClassReader;
import oracle.toplink.libraries.asm.ClassWriter;
import oracle.toplink.libraries.asm.Type;

/**
 * Annotation data contains an annotated type and its array of the element-value
 * pairs. Structure is in the following format:
 * 
 *   annotation {
 *     u2 type_index;
 *     u2 num_element_value_pairs;
 *     {
 *       u2 element_name_index;
 *       element_value value;
 *     } element_value_pairs[num_element_value_pairs];
 *   }
 * 
* The items of the annotation structure are as follows: *
*
type_index
*
The value of the type_index item must be a valid index into the constant_pool * table. The constant_pool entry at that index must be a CONSTANT_Utf8_info * structure representing a field descriptor representing the annotation * interface corresponding to the annotation represented by this annotation * structure.
*
num_element_value_pairs
*
The value of the num_element_value_pairs item gives the number of element-value * pairs in the annotation represented by this annotation structure. Note that a * maximum of 65535 element-value pairs may be contained in a single annotation.
*
element_value_pairs
*
Each value of the element_value_pairs table represents a single element-value * pair in the annotation represented by this annotation structure. * Each element_value_pairs entry contains the following two items: *
element_name_index
*
The value of the element_name_index item must be a valid index into the * constant_pool table. The constant_pool entry at that index must be a * CONSTANT_Utf8_info structure representing the name of the annotation type * element corresponding to this element_value_pairs entry.
*
value
*
The value item represents the value in the element-value pair represented by * this element_value_pairs entry.
*
* * * * The element_value structure is a discriminated union representing the value of a * element-value pair. It is used to represent values in all class file attributes * that describe annotations ( RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, * RuntimeVisibleParameterAnnotations, and RuntimeInvisibleParameterAnnotations). *

* The element_value structure has the following format: *

 *   element_value {
 *     u1 tag;
 *     union {
 *       u2   const_value_index;
 *       {
 *         u2   type_name_index;
 *         u2   const_name_index;
 *       } enum_const_value;
 *       u2   class_info_index;
 *       annotation annotation_value;
 *       {
 *         u2    num_values;
 *         element_value values[num_values];
 *       } array_value;
 *     } value;
 *   }
 * 
* The items of the element_value structure are as follows: *
*
tag
*
The tag item indicates the type of this annotation element-value pair. The letters * 'B', 'C', 'D', 'F', 'I', 'J', 'S', and 'Z' indicate a primitive type. These * letters are interpreted as BaseType characters (Table 4.2). The other legal * values for tag are listed with their interpretations in this table: *
 *     tag  value Element Type
 *     's'  String
 *     'e'  enum constant
 *     'c'  class
 *     '@'  annotation type
 *     '['  array
 *   
*
*
value
*
The value item represents the value of this annotation element. This item is * a union. The tag item, above, determines which item of the union is to be used: *
*
const_value_index
*
The const_value_index item is used if the tag item is one of 'B', 'C', 'D', * 'F', 'I', 'J', 'S', 'Z', or 's'. The value of the const_value_index item must * be a valid index into the constant_pool table. The constant_pool entry at * that index must be of the correct entry type for the field type designated by * the tag item, as specified in table 4.6, with one exception: if the tag is * 's', the the value of the const_value_index item must be the index of a * CONSTANT_Utf8 structure, rather than a CONSTANT_String.
*
enum_const_value
*
The enum_const_value item is used if the tag item is 'e'. The * enum_const_value item consists of the following two items: *
*
type_name_index
*
The value of the type_name_index item must be a valid index into the * constant_pool table. The constant_pool entry at that index must be a * CONSTANT_Utf8_info structure representing the binary name (JLS 13.1) of the * type of the enum constant represented by this element_value structure.
*
const_name_index
*
The value of the const_name_index item must be a valid index into the * constant_pool table. The constant_pool entry at that index must be a * CONSTANT_Utf8_info structure representing the simple name of the enum * constant represented by this element_value structure.
*
*
*
class_info_index
*
The class_info_index item is used if the tag item is 'c'. The * class_info_index item must be a valid index into the constant_pool table. * The constant_pool entry at that index must be a CONSTANT_Utf8_info * structure representing the return descriptor of the type that is * reified by the class represented by this element_value structure.
*
annotation_value
*
The annotation_value item is used if the tag item is '@'. The element_value * structure represents a "nested" {@link oracle.toplink.libraries.asm.attrs.Annotation annotation}.
*
array_value
*
The array_value item is used if the tag item is '['. The array_value item * consists of the following two items: *
*
num_values
*
The value of the num_values item gives the number of elements in the * array-typed value represented by this element_value structure. Note that a * maximum of 65535 elements are permitted in an array-typed element value.
*
values
*
Each element of the values table gives the value of an element of the * array-typed value represented by this {@link AnnotationElementValue element_value structure}.
*
*
*
*
*
* * @see JSR 175 : A Metadata * Facility for the Java Programming Language * * @author Eugene Kuleshov */ public class Annotation { /** * A fully qualified class name in internal form (see {@link Type Type}). */ public String type; /** * List of Object[]{name, value} pairs. * Where name is String and value is one of * Byte, Character, Double, * Float, Integer, Long, Short, * Boolean, String, * Annotation.EnumConstValue, Type, * Annotation or Object[]. */ public List elementValues = new ArrayList(); public Annotation() { } public Annotation( String type) { this.type = type; } public void add (String name, Object value) { elementValues.add(new Object[]{name, value}); } /** * Reads annotation data structures. * * @param cr the class that contains the attribute to be read. * @param off index of the first byte of the data structure. * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, * {@link ClassReader#readClass(int,char[]) readClass} or {@link * ClassReader#readConst readConst}. * * @return offset position in bytecode after reading annotation */ public int read (ClassReader cr, int off, char[] buf) { type = cr.readUTF8(off, buf); int numElementValuePairs = cr.readUnsignedShort(off + 2); off += 4; int[] aoff = new int[] { off}; for (int i = 0; i < numElementValuePairs; i++) { String elementName = cr.readUTF8(aoff[ 0], buf); aoff[ 0] += 2; elementValues.add(new Object[]{elementName, readValue(cr, aoff, buf)}); } return aoff[ 0]; } /** * Writes annotation data structures. * * @param bv the byte array form to store data structures. * @param cw the class to which this attribute must be added. This parameter * can be used to add to the constant pool of this class the items that * corresponds to this attribute. */ public void write (ByteVector bv, ClassWriter cw) { bv.putShort(cw.newUTF8(type)); bv.putShort(elementValues.size()); for (int i = 0; i < elementValues.size(); i++) { Object[] value = (Object[])elementValues.get(i); bv.putShort(cw.newUTF8((String)value[0])); writeValue(bv, value[1], cw); } } /** * Utility method to read List of annotations. Each element of annotations * List will have Annotation instance. * * @param annotations the List to store parameters annotations. * @param cr the class that contains the attribute to be read. * @param off index of the first byte of the data structure. * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, * {@link ClassReader#readClass(int,char[]) readClass} or {@link * ClassReader#readConst readConst}. * * @return offset position in bytecode after reading annotations */ public static int readAnnotations ( List annotations, ClassReader cr, int off, char[] buf) { int size = cr.readUnsignedShort(off); off += 2; for (int i = 0; i < size; i++) { Annotation ann = new Annotation(); off = ann.read(cr, off, buf); annotations.add(ann); } return off; } /** * Utility method to read List of parameters annotations. * * @param parameters the List to store parameters annotations. * Each element of the parameters List will have List of Annotation * instances. * @param cr the class that contains the attribute to be read. * @param off index of the first byte of the data structure. * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, * {@link ClassReader#readClass(int,char[]) readClass} or {@link * ClassReader#readConst readConst}. */ public static void readParameterAnnotations ( List parameters, ClassReader cr, int off, char[] buf) { int numParameters = cr.b[off++] & 0xff; for (int i = 0; i < numParameters; i++) { List annotations = new ArrayList(); off = Annotation.readAnnotations(annotations, cr, off, buf); parameters.add(annotations); } } /** * Utility method to write List of annotations. * * @param bv the byte array form to store data structures. * @param annotations the List of annotations to write. * Elements should be instances of the Annotation class. * @param cw the class to which this attribute must be added. This parameter * can be used to add to the constant pool of this class the items that * corresponds to this attribute. * * @return the byte array form with saved annotations. */ public static ByteVector writeAnnotations (ByteVector bv, List annotations, ClassWriter cw) { bv.putShort(annotations.size()); for (int i = 0; i < annotations.size(); i++) { ((Annotation)annotations.get(i)).write(bv, cw); } return bv; } /** * Utility method to write List of parameters annotations. * * @param bv the byte array form to store data structures. * @param parameters the List of parametars to write. Elements should be * instances of the List that contains instances of the Annotation class. * @param cw the class to which this attribute must be added. This parameter * can be used to add to the constant pool of this class the items that * corresponds to this attribute. * * @return the byte array form with saved annotations. */ public static ByteVector writeParametersAnnotations (ByteVector bv, List parameters, ClassWriter cw) { bv.putByte(parameters.size()); for (int i = 0; i < parameters.size(); i++) { writeAnnotations(bv, (List)parameters.get(i), cw); } return bv; } /** * Returns annotation values in the format described in JSR-175 for Java * source code. * * @param annotations a list of annotations. * @return annotation values in the format described in JSR-175 for Java * source code. */ public static String stringAnnotations (List annotations) { StringBuffer sb = new StringBuffer(); if (annotations.size() > 0) { for (int i = 0; i < annotations.size(); i++) { sb.append('\n').append(annotations.get(i)); } } else { sb.append( ""); } return sb.toString(); } /** * Returns parameter annotation values in the format described in JSR-175 * for Java source code. * * @param parameters a list of parameter annotations. * @return parameter annotation values in the format described in JSR-175 * for Java source code. */ public static String stringParameterAnnotations (List parameters) { StringBuffer sb = new StringBuffer(); String sep = ""; for (int i = 0; i < parameters.size(); i++) { sb.append(sep).append(stringAnnotations((List)parameters.get(i))); sep = ", "; } return sb.toString(); } /** * Reads element_value data structures. * * @param cr the class that contains the attribute to be read. * @param off index of the first byte of the data structure. * @param buf buffer to be used to call {@link ClassReader#readUTF8 readUTF8}, * {@link ClassReader#readClass(int,char[]) readClass} or {@link * ClassReader#readConst readConst}. * * @return offset position in bytecode after reading annotation */ protected static Object readValue (ClassReader cr, int[] off, char[] buf) { Object value = null; int tag = cr.readByte(off[ 0]++); switch (tag) { case 'I': // pointer to CONSTANT_Integer case 'J': // pointer to CONSTANT_Long case 'D': // pointer to CONSTANT_Double case 'F': // pointer to CONSTANT_Float value = cr.readConst(cr.readUnsignedShort(off[0]), buf); off[0] += 2; break; case 'B': // pointer to CONSTANT_Byte value = new Byte(( byte) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))); off[0] += 2; break; case 'C': // pointer to CONSTANT_Char value = new Character(( char) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))); off[0] += 2; break; case 'S': // pointer to CONSTANT_Short value = new Short(( short) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))); off[0] += 2; break; case 'Z': // pointer to CONSTANT_Boolean value = cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))==0 ? Boolean.FALSE : Boolean.TRUE; off[0] += 2; break; case 's': // pointer to CONSTANT_Utf8 value = cr.readUTF8(off[0], buf); off[0] += 2; break; case 'e': // enum_const_value // TODO verify the data structures value = new EnumConstValue(cr.readUTF8(off[0], buf), cr.readUTF8(off[0] + 2, buf)); off[0] += 4; break; case 'c': // class_info value = Type.getType(cr.readUTF8(off[0], buf)); off[0] += 2; break; case '@': // annotation_value value = new Annotation(); off[0] = ((Annotation) value).read(cr, off[0], buf); break; case '[': // array_value int size = cr.readUnsignedShort(off[0]); off[0] += 2; //PATCH for GF#1624 (From ASM Team) - handle empty annotation array value if(size==0) return new Object[0]; int childTag = cr.readByte( off[ 0]); switch( childTag) { case 'I': // pointer to CONSTANT_Integer { int[] v = new int[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = cr.readInt( cr.getItem( cr.readUnsignedShort(off[0]))); off[ 0] += 2; } value = v; } break; case 'J': // pointer to CONSTANT_Long { long[] v = new long[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = cr.readLong( cr.getItem( cr.readUnsignedShort(off[0]))); off[ 0] += 2; } value = v; } break; case 'D': // pointer to CONSTANT_Double { double[] v = new double[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = Double.longBitsToDouble( cr.readLong( cr.getItem( cr.readUnsignedShort(off[0])))); off[ 0] += 2; } value = v; } break; case 'F': // pointer to CONSTANT_Float { float[] v = new float[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = Float.intBitsToFloat( cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))); off[ 0] += 2; } value = v; } break; case 'B': // pointer to CONSTANT_Byte { byte[] v = new byte[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = ( byte) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0]))); off[ 0] += 2; } value = v; } break; case 'C': // pointer to CONSTANT_Char { char[] v = new char[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = ( char) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0]))); off[ 0] += 2; } value = v; } break; case 'S': // pointer to CONSTANT_Short { short[] v = new short[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = ( short) cr.readInt( cr.getItem( cr.readUnsignedShort(off[0]))); off[ 0] += 2; } value = v; } break; case 'Z': // pointer to CONSTANT_Boolean { boolean[] v = new boolean[ size]; for( int i = 0; i < size; i++) { off[ 0]++; // skip element tag v[ i] = cr.readInt( cr.getItem( cr.readUnsignedShort(off[0])))!=0; off[ 0] += 2; } value = v; } break; default: Object[] v = new Object[ size]; value = v; for (int i = 0; i < size; i++) { v[i] = readValue(cr, off, buf); } break; } } return value; } /** * Writes element_value data structures. * * @param bv the byte array form to store data structures. * @param value * @param cw the class to which this attribute must be added. This parameter * can be used to add to the constant pool of this class the items that * corresponds to this attribute. * @return bv. */ protected static ByteVector writeValue (ByteVector bv, Object value, ClassWriter cw) { if (value instanceof String) { bv.putByte('s'); bv.putShort(cw.newUTF8((String)value)); } else if (value instanceof EnumConstValue) { bv.putByte('e'); bv.putShort(cw.newUTF8(((EnumConstValue)value).typeName)); bv.putShort(cw.newUTF8(((EnumConstValue)value).constName)); } else if (value instanceof Type) { bv.putByte('c'); bv.putShort(cw.newUTF8(((Type)value).getDescriptor())); } else if (value instanceof Annotation) { bv.putByte('@'); ((Annotation)value).write(bv, cw); } else if (value instanceof Object[]) { bv.putByte('['); Object[] v = (Object[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { writeValue(bv, v[i], cw); } } else if( value instanceof byte[]) { bv.putByte('['); byte[] v = (byte[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('B'); bv.putShort(cw.newConstInt(v[i])); } } else if( value instanceof short[]) { bv.putByte('['); short[] v = (short[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('S'); bv.putShort(cw.newConstInt(v[i])); } } else if( value instanceof int[]) { bv.putByte('['); int[] v = (int[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('I'); bv.putShort(cw.newConstInt(v[i])); } } else if( value instanceof char[]) { bv.putByte('['); char[] v = (char[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('C'); bv.putShort(cw.newConstInt(v[i])); } } else if( value instanceof boolean[]) { bv.putByte('['); boolean[] v = (boolean[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('Z'); bv.putShort(cw.newConstInt(v[i] ? 1 : 0)); } } else if( value instanceof long[]) { bv.putByte('['); long[] v = (long[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('J'); bv.putShort(cw.newConstLong(v[i])); } } else if( value instanceof float[]) { bv.putByte('['); float[] v = (float[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('F'); bv.putShort(cw.newConstFloat(v[i])); } } else if( value instanceof double[]) { bv.putByte('['); double[] v = (double[])value; bv.putShort(v.length); for (int i = 0; i < v.length; i++) { bv.putByte('D'); bv.putShort(cw.newConstDouble(v[i])); } } else { int tag = -1; if (value instanceof Integer) { tag = 'I'; } else if (value instanceof Byte) { tag = 'B'; } else if (value instanceof Character) { tag = 'C'; } else if (value instanceof Double) { tag = 'D'; } else if (value instanceof Float) { tag = 'F'; } else if (value instanceof Long) { tag = 'J'; } else if (value instanceof Short) { tag = 'S'; } else if (value instanceof Boolean) { tag = 'Z'; } bv.putByte(tag); bv.putShort(cw.newConst(value)); } return bv; } /** * Returns value in the format described in JSR-175 for Java source code. * * @return value in the format described in JSR-175 for Java source code. */ public String toString () { StringBuffer sb = new StringBuffer("@").append(type); // shorthand syntax for marker annotation if (elementValues.size() > 0) { sb.append(" ( "); String sep = ""; for (int i = 0; i < elementValues.size(); i++) { Object[] value = (Object[])elementValues.get(i); // using shorthand syntax for single-element annotation if ( !( elementValues.size()==1 || "value".equals( elementValues.get( 0)))) { sb.append(sep).append(value[0]).append(" = "); } if(value[1] instanceof Object[]) { Object[] v = ( Object[]) value[1]; sb.append("{"); String sep2 = ""; for( int j = 0; j < v.length; j++) { sb.append(sep2).append(v[ j]); sep2 = ", "; } sb.append("}"); } else { sb.append(value[1]); } sep = ", "; } sb.append(" )"); } return sb.toString(); } /** * Container class used to store enum_const_value structure. */ public static class EnumConstValue { public String typeName; public String constName; public EnumConstValue (String typeName, String constName) { this.typeName = typeName; this.constName = constName; } public String toString () { return typeName + ":" + constName; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy