/biz.aQute.eclipse.compiler/src/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java
Java | 379 lines | 322 code | 5 blank | 52 comment | 42 complexity | 28582bcae33bd78f1e220b72613dd88c MD5 | raw file
- /*******************************************************************************
- * Copyright (c) 2005, 2007 BEA Systems, Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * tyeung@bea.com - initial API and implementation
- *******************************************************************************/
- package org.eclipse.jdt.internal.compiler.classfmt;
- import org.eclipse.jdt.core.compiler.CharOperation;
- import org.eclipse.jdt.internal.compiler.ast.Annotation;
- import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
- import org.eclipse.jdt.internal.compiler.env.*;
- import org.eclipse.jdt.internal.compiler.impl.*;
- import org.eclipse.jdt.internal.compiler.lookup.TagBits;
- public class AnnotationInfo extends ClassFileStruct implements IBinaryAnnotation {
- /** The name of the annotation type */
- private char[] typename;
- /**
- * null until this annotation is initialized
- * @see #getElementValuePairs()
- */
- private ElementValuePairInfo[] pairs;
- long standardAnnotationTagBits = 0;
- int readOffset = 0;
- static Object[] EmptyValueArray = new Object[0];
- AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset) {
- super(classFileBytes, contantPoolOffsets, offset);
- }
- /**
- * @param classFileBytes
- * @param offset the offset into <code>classFileBytes</code> for the "type_index" of the annotation attribute.
- * @param populate <code>true</code> to indicate to build out the annotation structure.
- */
- AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset, boolean runtimeVisible, boolean populate) {
- this(classFileBytes, contantPoolOffsets, offset);
- if (populate)
- decodeAnnotation();
- else
- this.readOffset = scanAnnotation(0, runtimeVisible, true);
- }
- private void decodeAnnotation() {
- this.readOffset = 0;
- int utf8Offset = this.constantPoolOffsets[u2At(0)] - this.structOffset;
- this.typename = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- int numberOfPairs = u2At(2);
- // u2 type_index + u2 num_member_value_pair
- this.readOffset += 4;
- this.pairs = numberOfPairs == 0 ? ElementValuePairInfo.NoMembers : new ElementValuePairInfo[numberOfPairs];
- for (int i = 0; i < numberOfPairs; i++) {
- // u2 member_name_index;
- utf8Offset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- char[] membername = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- this.readOffset += 2;
- Object value = decodeDefaultValue();
- this.pairs[i] = new ElementValuePairInfo(membername, value);
- }
- }
- Object decodeDefaultValue() {
- Object value = null;
- // u1 tag;
- int tag = u1At(this.readOffset);
- this.readOffset++;
- int constValueOffset = -1;
- switch (tag) {
- case 'Z': // boolean constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = BooleanConstant.fromValue(i4At(constValueOffset + 1) == 1);
- this.readOffset += 2;
- break;
- case 'I': // integer constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = IntConstant.fromValue(i4At(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'C': // char constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = CharConstant.fromValue((char) i4At(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'B': // byte constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = ByteConstant.fromValue((byte) i4At(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'S': // short constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = ShortConstant.fromValue((short) i4At(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'D': // double constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = DoubleConstant.fromValue(doubleAt(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'F': // float constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = FloatConstant.fromValue(floatAt(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 'J': // long constant
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = LongConstant.fromValue(i8At(constValueOffset + 1));
- this.readOffset += 2;
- break;
- case 's': // String
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- value = StringConstant.fromValue(String.valueOf(utf8At(constValueOffset + 3, u2At(constValueOffset + 1))));
- this.readOffset += 2;
- break;
- case 'e':
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- char[] typeName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
- this.readOffset += 2;
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- char[] constName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
- this.readOffset += 2;
- value = new EnumConstantSignature(typeName, constName);
- break;
- case 'c':
- constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
- char[] className = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
- value = new ClassSignature(className);
- this.readOffset += 2;
- break;
- case '@':
- value = new AnnotationInfo(this.reference, this.constantPoolOffsets, this.readOffset + this.structOffset, false, true);
- this.readOffset += ((AnnotationInfo) value).readOffset;
- break;
- case '[':
- int numberOfValues = u2At(this.readOffset);
- this.readOffset += 2;
- if (numberOfValues == 0) {
- value = EmptyValueArray;
- } else {
- Object[] arrayElements = new Object[numberOfValues];
- value = arrayElements;
- for (int i = 0; i < numberOfValues; i++)
- arrayElements[i] = decodeDefaultValue();
- }
- break;
- default:
- throw new IllegalStateException("Unrecognized tag " + (char) tag); //$NON-NLS-1$
- }
- return value;
- }
- public IBinaryElementValuePair[] getElementValuePairs() {
- if (this.pairs == null)
- initialize();
- return this.pairs;
- }
- public char[] getTypeName() {
- return this.typename;
- }
- void initialize() {
- if (this.pairs == null)
- decodeAnnotation();
- }
- private int readRetentionPolicy(int offset) {
- int currentOffset = offset;
- int tag = u1At(currentOffset);
- currentOffset++;
- switch (tag) {
- case 'e':
- int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
- char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- currentOffset += 2;
- if (typeName.length == 38 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTIONPOLICY)) {
- utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
- char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- this.standardAnnotationTagBits |= Annotation.getRetentionPolicy(constName);
- }
- currentOffset += 2;
- break;
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'I':
- case 'J':
- case 'S':
- case 'Z':
- case 's':
- case 'c':
- currentOffset += 2;
- break;
- case '@':
- // none of the supported standard annotation are in the nested
- // level.
- currentOffset = scanAnnotation(currentOffset, false, false);
- break;
- case '[':
- int numberOfValues = u2At(currentOffset);
- currentOffset += 2;
- for (int i = 0; i < numberOfValues; i++)
- currentOffset = scanElementValue(currentOffset);
- break;
- default:
- throw new IllegalStateException();
- }
- return currentOffset;
- }
- private int readTargetValue(int offset) {
- int currentOffset = offset;
- int tag = u1At(currentOffset);
- currentOffset++;
- switch (tag) {
- case 'e':
- int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
- char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- currentOffset += 2;
- if (typeName.length == 34 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_ELEMENTTYPE)) {
- utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
- char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- this.standardAnnotationTagBits |= Annotation.getTargetElementType(constName);
- }
- currentOffset += 2;
- break;
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'I':
- case 'J':
- case 'S':
- case 'Z':
- case 's':
- case 'c':
- currentOffset += 2;
- break;
- case '@':
- // none of the supported standard annotation are in the nested
- // level.
- currentOffset = scanAnnotation(currentOffset, false, false);
- break;
- case '[':
- int numberOfValues = u2At(currentOffset);
- currentOffset += 2;
- if (numberOfValues == 0) {
- this.standardAnnotationTagBits |= TagBits.AnnotationTarget;
- } else {
- for (int i = 0; i < numberOfValues; i++)
- currentOffset = readTargetValue(currentOffset);
- }
- break;
- default:
- throw new IllegalStateException();
- }
- return currentOffset;
- }
- /**
- * Read through this annotation in order to figure out the necessary tag
- * bits and the length of this annotation. The data structure will not be
- * flushed out.
- *
- * The tag bits are derived from the following (supported) standard
- * annotation. java.lang.annotation.Documented,
- * java.lang.annotation.Retention, java.lang.annotation.Target, and
- * java.lang.Deprecated
- *
- * @param expectRuntimeVisibleAnno
- * <code>true</cod> to indicate that this is a runtime-visible annotation
- * @param toplevel <code>false</code> to indicate that an nested annotation is read.
- * <code>true</code> otherwise
- * @return the next offset to read.
- */
- private int scanAnnotation(int offset, boolean expectRuntimeVisibleAnno, boolean toplevel) {
- int currentOffset = offset;
- int utf8Offset = this.constantPoolOffsets[u2At(offset)] - this.structOffset;
- char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
- if (toplevel)
- this.typename = typeName;
- int numberOfPairs = u2At(offset + 2);
- // u2 type_index + u2 number_member_value_pair
- currentOffset += 4;
- if (expectRuntimeVisibleAnno && toplevel) {
- switch (typeName.length) {
- case 22:
- if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_DEPRECATED)) {
- this.standardAnnotationTagBits |= TagBits.AnnotationDeprecated;
- return currentOffset;
- }
- break;
- case 29:
- if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_TARGET)) {
- currentOffset += 2;
- return readTargetValue(currentOffset);
- }
- break;
- case 33:
- if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_DOCUMENTED)) {
- this.standardAnnotationTagBits |= TagBits.AnnotationDocumented;
- return currentOffset;
- }
- break;
- case 32:
- if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTION)) {
- currentOffset += 2;
- return readRetentionPolicy(currentOffset);
- }
- if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_INHERITED)) {
- this.standardAnnotationTagBits |= TagBits.AnnotationInherited;
- return currentOffset;
- }
- break;
- }
- }
- for (int i = 0; i < numberOfPairs; i++) {
- // u2 member_name_index
- currentOffset += 2;
- currentOffset = scanElementValue(currentOffset);
- }
- return currentOffset;
- }
- /**
- * @param offset
- * the offset to start reading.
- * @return the next offset to read.
- */
- private int scanElementValue(int offset) {
- int currentOffset = offset;
- int tag = u1At(currentOffset);
- currentOffset++;
- switch (tag) {
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'I':
- case 'J':
- case 'S':
- case 'Z':
- case 's':
- case 'c':
- currentOffset += 2;
- break;
- case 'e':
- currentOffset += 4;
- break;
- case '@':
- // none of the supported standard annotation are in the nested
- // level.
- currentOffset = scanAnnotation(currentOffset, false, false);
- break;
- case '[':
- int numberOfValues = u2At(currentOffset);
- currentOffset += 2;
- for (int i = 0; i < numberOfValues; i++)
- currentOffset = scanElementValue(currentOffset);
- break;
- default:
- throw new IllegalStateException();
- }
- return currentOffset;
- }
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.append('@');
- buffer.append(this.typename);
- if (this.pairs != null) {
- buffer.append('(');
- buffer.append("\n\t"); //$NON-NLS-1$
- for (int i = 0, len = this.pairs.length; i < len; i++) {
- if (i > 0)
- buffer.append(",\n\t"); //$NON-NLS-1$
- buffer.append(this.pairs[i]);
- }
- buffer.append(')');
- }
- return buffer.toString();
- }
- }