attributeAndSize = getAttributeAndSize(offset);
result[i] = attributeAndSize.fst;
offset += attributeAndSize.snd;
}
return result;
}
/**
*
* param_annotations {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 num_parameters;
* {
* u2 num_annotations;
* annotation annotations[num_annotations];
* } parameter_annotations[num_parameters];
*
*/
public AnnotationAttribute[][] getAllParameterAnnotations() throws InvalidClassFileException {
int numParamOffset = beginOffset + 6;
checkSize(numParamOffset, 1);
int paramCount = cr.getByte(numParamOffset);
AnnotationAttribute[][] result = new AnnotationAttribute[paramCount][];
// skip attribute_name_index, attribute_length, and num_parameters
int offset = beginOffset + 7;
for (int i = 0; i < result.length; i++) {
checkSize(offset, 2);
result[i] = new AnnotationAttribute[cr.getUShort(offset)];
offset += 2;
for (int j = 0; j < result[i].length; j++) {
Pair attributeAndSize = getAttributeAndSize(offset);
result[i][j] = attributeAndSize.fst;
offset += attributeAndSize.snd;
}
}
return result;
}
/**
*
* annotation {
* u2 type_index;
* u2 num_element_value_pairs;
* { u2 element_name_index;
* element_value value;
* } element_value_pairs[num_element_value_pairs]
*
*
* @throws InvalidClassFileException
*/
private Pair getAttributeAndSize(int begin) throws InvalidClassFileException {
String type = getUtf8ConstantPoolValue(begin);
int numElementValuePairs = cr.getUShort(begin + 2);
int size = 4;
int offset = begin + 4;
Map elementName2Val = HashMapFactory.make();
for (int i = 0; i < numElementValuePairs; i++) {
String elementName = getUtf8ConstantPoolValue(offset);
offset += 2;
Pair elementValAndSize = readElementValueAndSize(offset);
offset += elementValAndSize.snd;
size += elementValAndSize.snd + 2;
elementName2Val.put(elementName, elementValAndSize.fst);
}
return Pair.make(new AnnotationAttribute(type, elementName2Val), size);
}
/**
* Representation of an annotation attribute. An annotation has the following
* format in the bytecode:
*
*
* annotation {
* u2 type_index;
* u2 num_element_value_pairs;
* { u2 element_name_index;
* element_value value;
* } element_value_pairs[num_element_value_pairs];
*
*
* See the JVM specification section 4.7.16 for details.
*
* This class implements {@link ElementValue} to handle nested annotations.
*/
public static class AnnotationAttribute implements ElementValue {
/**
* the type of the annotation
*/
public final String type;
/**
* the arguments to the annotation
*/
public final Map elementValues;
public AnnotationAttribute(String type, Map elementValues) {
super();
this.type = type;
this.elementValues = elementValues;
}
@Override
public String toString() {
return "AnnotationElementValue [type=" + type + ", elementValues=" + elementValues + "]";
}
}
/**
*
* 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;
*
*
* A constant value (including class info) is represented by a
* {@link ConstantElementValue}. An enum constant value is represented by an
* {@link EnumElementValue}. An array value is represented by an
* {@link ArrayElementValue}. Finally, a nested annotation is represented by
* an {@link AnnotationAttribute}.
*
* @throws InvalidClassFileException
* @throws IllegalArgumentException
*/
private Pair readElementValueAndSize(int offset) throws IllegalArgumentException,
InvalidClassFileException {
char tag = (char) cr.getByte(offset);
// meaning of this short depends on the tag
int nextShort = cr.getUShort(offset + 1);
switch (tag) {
case 'B':
case 'C':
case 'I':
case 'S':
case 'Z':
return Pair. make(new ConstantElementValue(cr.getCP().getCPInt(nextShort)), 3);
case 'J':
return Pair. make(new ConstantElementValue(cr.getCP().getCPLong(nextShort)), 3);
case 'D':
return Pair. make(new ConstantElementValue(cr.getCP().getCPDouble(nextShort)), 3);
case 'F':
return Pair. make(new ConstantElementValue(cr.getCP().getCPFloat(nextShort)), 3);
case 's': // string
case 'c': // class; just represent as a constant element with the type name
return Pair. make(new ConstantElementValue(cr.getCP().getCPUtf8(nextShort)), 3);
case 'e': // enum
return Pair. make(
new EnumElementValue(cr.getCP().getCPUtf8(nextShort), cr.getCP().getCPUtf8(cr.getUShort(offset + 3))), 5);
case '[': // array
int numValues = nextShort;
int numArrayBytes = 3; // start with 3 for the tag and num_values bytes
ElementValue[] vals = new ElementValue[numValues];
// start curOffset at beginning of array values
int curArrayOffset = offset + 3;
for (int i = 0; i < numValues; i++) {
Pair arrayElemValueAndSize = readElementValueAndSize(curArrayOffset);
vals[i] = arrayElemValueAndSize.fst;
curArrayOffset += arrayElemValueAndSize.snd;
numArrayBytes += arrayElemValueAndSize.snd;
}
return Pair. make(new ArrayElementValue(vals), numArrayBytes);
case '@': // annotation
Pair attributeAndSize = getAttributeAndSize(offset + 1);
// add 1 to size for the tag
return Pair. make(attributeAndSize.fst, attributeAndSize.snd + 1);
default:
assert false;
return null;
}
}
// //////////////
// utility methods for reading well-known annotation types
// //////////////
public static enum AnnotationType {
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations
}
public static boolean isKnownAnnotation(String name) {
for (AnnotationType t : AnnotationType.values()) {
if (t.name().equals(name)) {
return true;
}
}
return false;
}
public static AnnotationsReader getReaderForAnnotation(AnnotationType type, ClassReader.AttrIterator iter) {
// search for the desired attribute
final String attrName = type.toString();
try {
for (; iter.isValid(); iter.advance()) {
if (iter.getName().equals(attrName)) {
return new AnnotationsReader(iter, attrName);
}
}
} catch (InvalidClassFileException e) {
Assertions.UNREACHABLE();
}
return null;
}
}