PageRenderTime 29ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/biz.aQute.eclipse.compiler/src/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java

https://github.com/juretta/bnd
Java | 379 lines | 322 code | 5 blank | 52 comment | 42 complexity | 28582bcae33bd78f1e220b72613dd88c MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2005, 2007 BEA Systems, Inc.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * tyeung@bea.com - initial API and implementation
  10. *******************************************************************************/
  11. package org.eclipse.jdt.internal.compiler.classfmt;
  12. import org.eclipse.jdt.core.compiler.CharOperation;
  13. import org.eclipse.jdt.internal.compiler.ast.Annotation;
  14. import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
  15. import org.eclipse.jdt.internal.compiler.env.*;
  16. import org.eclipse.jdt.internal.compiler.impl.*;
  17. import org.eclipse.jdt.internal.compiler.lookup.TagBits;
  18. public class AnnotationInfo extends ClassFileStruct implements IBinaryAnnotation {
  19. /** The name of the annotation type */
  20. private char[] typename;
  21. /**
  22. * null until this annotation is initialized
  23. * @see #getElementValuePairs()
  24. */
  25. private ElementValuePairInfo[] pairs;
  26. long standardAnnotationTagBits = 0;
  27. int readOffset = 0;
  28. static Object[] EmptyValueArray = new Object[0];
  29. AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset) {
  30. super(classFileBytes, contantPoolOffsets, offset);
  31. }
  32. /**
  33. * @param classFileBytes
  34. * @param offset the offset into <code>classFileBytes</code> for the "type_index" of the annotation attribute.
  35. * @param populate <code>true</code> to indicate to build out the annotation structure.
  36. */
  37. AnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset, boolean runtimeVisible, boolean populate) {
  38. this(classFileBytes, contantPoolOffsets, offset);
  39. if (populate)
  40. decodeAnnotation();
  41. else
  42. this.readOffset = scanAnnotation(0, runtimeVisible, true);
  43. }
  44. private void decodeAnnotation() {
  45. this.readOffset = 0;
  46. int utf8Offset = this.constantPoolOffsets[u2At(0)] - this.structOffset;
  47. this.typename = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  48. int numberOfPairs = u2At(2);
  49. // u2 type_index + u2 num_member_value_pair
  50. this.readOffset += 4;
  51. this.pairs = numberOfPairs == 0 ? ElementValuePairInfo.NoMembers : new ElementValuePairInfo[numberOfPairs];
  52. for (int i = 0; i < numberOfPairs; i++) {
  53. // u2 member_name_index;
  54. utf8Offset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  55. char[] membername = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  56. this.readOffset += 2;
  57. Object value = decodeDefaultValue();
  58. this.pairs[i] = new ElementValuePairInfo(membername, value);
  59. }
  60. }
  61. Object decodeDefaultValue() {
  62. Object value = null;
  63. // u1 tag;
  64. int tag = u1At(this.readOffset);
  65. this.readOffset++;
  66. int constValueOffset = -1;
  67. switch (tag) {
  68. case 'Z': // boolean constant
  69. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  70. value = BooleanConstant.fromValue(i4At(constValueOffset + 1) == 1);
  71. this.readOffset += 2;
  72. break;
  73. case 'I': // integer constant
  74. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  75. value = IntConstant.fromValue(i4At(constValueOffset + 1));
  76. this.readOffset += 2;
  77. break;
  78. case 'C': // char constant
  79. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  80. value = CharConstant.fromValue((char) i4At(constValueOffset + 1));
  81. this.readOffset += 2;
  82. break;
  83. case 'B': // byte constant
  84. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  85. value = ByteConstant.fromValue((byte) i4At(constValueOffset + 1));
  86. this.readOffset += 2;
  87. break;
  88. case 'S': // short constant
  89. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  90. value = ShortConstant.fromValue((short) i4At(constValueOffset + 1));
  91. this.readOffset += 2;
  92. break;
  93. case 'D': // double constant
  94. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  95. value = DoubleConstant.fromValue(doubleAt(constValueOffset + 1));
  96. this.readOffset += 2;
  97. break;
  98. case 'F': // float constant
  99. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  100. value = FloatConstant.fromValue(floatAt(constValueOffset + 1));
  101. this.readOffset += 2;
  102. break;
  103. case 'J': // long constant
  104. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  105. value = LongConstant.fromValue(i8At(constValueOffset + 1));
  106. this.readOffset += 2;
  107. break;
  108. case 's': // String
  109. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  110. value = StringConstant.fromValue(String.valueOf(utf8At(constValueOffset + 3, u2At(constValueOffset + 1))));
  111. this.readOffset += 2;
  112. break;
  113. case 'e':
  114. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  115. char[] typeName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
  116. this.readOffset += 2;
  117. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  118. char[] constName = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
  119. this.readOffset += 2;
  120. value = new EnumConstantSignature(typeName, constName);
  121. break;
  122. case 'c':
  123. constValueOffset = this.constantPoolOffsets[u2At(this.readOffset)] - this.structOffset;
  124. char[] className = utf8At(constValueOffset + 3, u2At(constValueOffset + 1));
  125. value = new ClassSignature(className);
  126. this.readOffset += 2;
  127. break;
  128. case '@':
  129. value = new AnnotationInfo(this.reference, this.constantPoolOffsets, this.readOffset + this.structOffset, false, true);
  130. this.readOffset += ((AnnotationInfo) value).readOffset;
  131. break;
  132. case '[':
  133. int numberOfValues = u2At(this.readOffset);
  134. this.readOffset += 2;
  135. if (numberOfValues == 0) {
  136. value = EmptyValueArray;
  137. } else {
  138. Object[] arrayElements = new Object[numberOfValues];
  139. value = arrayElements;
  140. for (int i = 0; i < numberOfValues; i++)
  141. arrayElements[i] = decodeDefaultValue();
  142. }
  143. break;
  144. default:
  145. throw new IllegalStateException("Unrecognized tag " + (char) tag); //$NON-NLS-1$
  146. }
  147. return value;
  148. }
  149. public IBinaryElementValuePair[] getElementValuePairs() {
  150. if (this.pairs == null)
  151. initialize();
  152. return this.pairs;
  153. }
  154. public char[] getTypeName() {
  155. return this.typename;
  156. }
  157. void initialize() {
  158. if (this.pairs == null)
  159. decodeAnnotation();
  160. }
  161. private int readRetentionPolicy(int offset) {
  162. int currentOffset = offset;
  163. int tag = u1At(currentOffset);
  164. currentOffset++;
  165. switch (tag) {
  166. case 'e':
  167. int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
  168. char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  169. currentOffset += 2;
  170. if (typeName.length == 38 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTIONPOLICY)) {
  171. utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
  172. char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  173. this.standardAnnotationTagBits |= Annotation.getRetentionPolicy(constName);
  174. }
  175. currentOffset += 2;
  176. break;
  177. case 'B':
  178. case 'C':
  179. case 'D':
  180. case 'F':
  181. case 'I':
  182. case 'J':
  183. case 'S':
  184. case 'Z':
  185. case 's':
  186. case 'c':
  187. currentOffset += 2;
  188. break;
  189. case '@':
  190. // none of the supported standard annotation are in the nested
  191. // level.
  192. currentOffset = scanAnnotation(currentOffset, false, false);
  193. break;
  194. case '[':
  195. int numberOfValues = u2At(currentOffset);
  196. currentOffset += 2;
  197. for (int i = 0; i < numberOfValues; i++)
  198. currentOffset = scanElementValue(currentOffset);
  199. break;
  200. default:
  201. throw new IllegalStateException();
  202. }
  203. return currentOffset;
  204. }
  205. private int readTargetValue(int offset) {
  206. int currentOffset = offset;
  207. int tag = u1At(currentOffset);
  208. currentOffset++;
  209. switch (tag) {
  210. case 'e':
  211. int utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
  212. char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  213. currentOffset += 2;
  214. if (typeName.length == 34 && CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_ELEMENTTYPE)) {
  215. utf8Offset = this.constantPoolOffsets[u2At(currentOffset)] - this.structOffset;
  216. char[] constName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  217. this.standardAnnotationTagBits |= Annotation.getTargetElementType(constName);
  218. }
  219. currentOffset += 2;
  220. break;
  221. case 'B':
  222. case 'C':
  223. case 'D':
  224. case 'F':
  225. case 'I':
  226. case 'J':
  227. case 'S':
  228. case 'Z':
  229. case 's':
  230. case 'c':
  231. currentOffset += 2;
  232. break;
  233. case '@':
  234. // none of the supported standard annotation are in the nested
  235. // level.
  236. currentOffset = scanAnnotation(currentOffset, false, false);
  237. break;
  238. case '[':
  239. int numberOfValues = u2At(currentOffset);
  240. currentOffset += 2;
  241. if (numberOfValues == 0) {
  242. this.standardAnnotationTagBits |= TagBits.AnnotationTarget;
  243. } else {
  244. for (int i = 0; i < numberOfValues; i++)
  245. currentOffset = readTargetValue(currentOffset);
  246. }
  247. break;
  248. default:
  249. throw new IllegalStateException();
  250. }
  251. return currentOffset;
  252. }
  253. /**
  254. * Read through this annotation in order to figure out the necessary tag
  255. * bits and the length of this annotation. The data structure will not be
  256. * flushed out.
  257. *
  258. * The tag bits are derived from the following (supported) standard
  259. * annotation. java.lang.annotation.Documented,
  260. * java.lang.annotation.Retention, java.lang.annotation.Target, and
  261. * java.lang.Deprecated
  262. *
  263. * @param expectRuntimeVisibleAnno
  264. * <code>true</cod> to indicate that this is a runtime-visible annotation
  265. * @param toplevel <code>false</code> to indicate that an nested annotation is read.
  266. * <code>true</code> otherwise
  267. * @return the next offset to read.
  268. */
  269. private int scanAnnotation(int offset, boolean expectRuntimeVisibleAnno, boolean toplevel) {
  270. int currentOffset = offset;
  271. int utf8Offset = this.constantPoolOffsets[u2At(offset)] - this.structOffset;
  272. char[] typeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
  273. if (toplevel)
  274. this.typename = typeName;
  275. int numberOfPairs = u2At(offset + 2);
  276. // u2 type_index + u2 number_member_value_pair
  277. currentOffset += 4;
  278. if (expectRuntimeVisibleAnno && toplevel) {
  279. switch (typeName.length) {
  280. case 22:
  281. if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_DEPRECATED)) {
  282. this.standardAnnotationTagBits |= TagBits.AnnotationDeprecated;
  283. return currentOffset;
  284. }
  285. break;
  286. case 29:
  287. if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_TARGET)) {
  288. currentOffset += 2;
  289. return readTargetValue(currentOffset);
  290. }
  291. break;
  292. case 33:
  293. if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_DOCUMENTED)) {
  294. this.standardAnnotationTagBits |= TagBits.AnnotationDocumented;
  295. return currentOffset;
  296. }
  297. break;
  298. case 32:
  299. if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_RETENTION)) {
  300. currentOffset += 2;
  301. return readRetentionPolicy(currentOffset);
  302. }
  303. if (CharOperation.equals(typeName, ConstantPool.JAVA_LANG_ANNOTATION_INHERITED)) {
  304. this.standardAnnotationTagBits |= TagBits.AnnotationInherited;
  305. return currentOffset;
  306. }
  307. break;
  308. }
  309. }
  310. for (int i = 0; i < numberOfPairs; i++) {
  311. // u2 member_name_index
  312. currentOffset += 2;
  313. currentOffset = scanElementValue(currentOffset);
  314. }
  315. return currentOffset;
  316. }
  317. /**
  318. * @param offset
  319. * the offset to start reading.
  320. * @return the next offset to read.
  321. */
  322. private int scanElementValue(int offset) {
  323. int currentOffset = offset;
  324. int tag = u1At(currentOffset);
  325. currentOffset++;
  326. switch (tag) {
  327. case 'B':
  328. case 'C':
  329. case 'D':
  330. case 'F':
  331. case 'I':
  332. case 'J':
  333. case 'S':
  334. case 'Z':
  335. case 's':
  336. case 'c':
  337. currentOffset += 2;
  338. break;
  339. case 'e':
  340. currentOffset += 4;
  341. break;
  342. case '@':
  343. // none of the supported standard annotation are in the nested
  344. // level.
  345. currentOffset = scanAnnotation(currentOffset, false, false);
  346. break;
  347. case '[':
  348. int numberOfValues = u2At(currentOffset);
  349. currentOffset += 2;
  350. for (int i = 0; i < numberOfValues; i++)
  351. currentOffset = scanElementValue(currentOffset);
  352. break;
  353. default:
  354. throw new IllegalStateException();
  355. }
  356. return currentOffset;
  357. }
  358. public String toString() {
  359. StringBuffer buffer = new StringBuffer();
  360. buffer.append('@');
  361. buffer.append(this.typename);
  362. if (this.pairs != null) {
  363. buffer.append('(');
  364. buffer.append("\n\t"); //$NON-NLS-1$
  365. for (int i = 0, len = this.pairs.length; i < len; i++) {
  366. if (i > 0)
  367. buffer.append(",\n\t"); //$NON-NLS-1$
  368. buffer.append(this.pairs[i]);
  369. }
  370. buffer.append(')');
  371. }
  372. return buffer.toString();
  373. }
  374. }