You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WildAnnotationTypePattern.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /* *******************************************************************
  2. * Copyright (c) 2004 IBM Corporation.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * ******************************************************************/
  10. package org.aspectj.weaver.patterns;
  11. import java.io.IOException;
  12. import java.util.HashMap;
  13. import java.util.Iterator;
  14. import java.util.Map;
  15. import java.util.Set;
  16. import org.aspectj.bridge.IMessage;
  17. import org.aspectj.bridge.MessageUtil;
  18. import org.aspectj.util.FuzzyBoolean;
  19. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  20. import org.aspectj.weaver.AnnotatedElement;
  21. import org.aspectj.weaver.BCException;
  22. import org.aspectj.weaver.CompressingDataOutputStream;
  23. import org.aspectj.weaver.ISourceContext;
  24. import org.aspectj.weaver.ResolvedMember;
  25. import org.aspectj.weaver.ResolvedType;
  26. import org.aspectj.weaver.UnresolvedType;
  27. import org.aspectj.weaver.VersionedDataInputStream;
  28. import org.aspectj.weaver.WeaverMessages;
  29. import org.aspectj.weaver.World;
  30. /**
  31. * @author colyer
  32. * @author Andy Clement
  33. */
  34. public class WildAnnotationTypePattern extends AnnotationTypePattern {
  35. private TypePattern typePattern;
  36. private boolean resolved = false;
  37. Map<String, String> annotationValues;
  38. public WildAnnotationTypePattern(TypePattern typePattern) {
  39. super();
  40. this.typePattern = typePattern;
  41. this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
  42. }
  43. public WildAnnotationTypePattern(TypePattern typePattern, Map<String, String> annotationValues) {
  44. super();
  45. this.typePattern = typePattern;
  46. this.annotationValues = annotationValues;
  47. // PVAL make the location be from start of type pattern to end of values
  48. this.setLocation(typePattern.getSourceContext(), typePattern.start, typePattern.end);
  49. }
  50. public TypePattern getTypePattern() {
  51. return typePattern;
  52. }
  53. /*
  54. * (non-Javadoc)
  55. *
  56. * @see org.aspectj.weaver.patterns.AnnotationTypePattern#matches(org.aspectj.weaver.AnnotatedElement)
  57. */
  58. @Override
  59. public FuzzyBoolean matches(AnnotatedElement annotated) {
  60. return matches(annotated, null);
  61. }
  62. /**
  63. * Resolve any annotation values specified, checking they are all well formed (valid names, valid values)
  64. *
  65. * @param annotationType the annotation type for which the values have been specified
  66. * @param scope the scope within which to resolve type references (eg. Color.GREEN)
  67. */
  68. protected void resolveAnnotationValues(ResolvedType annotationType, IScope scope) {
  69. if (annotationValues == null) {
  70. return;
  71. }
  72. // Check any values specified are OK:
  73. // - the value names are for valid annotation fields
  74. // - the specified values are of the correct type
  75. // - for enums, check the specified values can be resolved in the specified scope
  76. Map<String,String> replacementValues = new HashMap<String,String>();
  77. Set<String> keys = annotationValues.keySet();
  78. ResolvedMember[] ms = annotationType.getDeclaredMethods();
  79. for (String k: keys) {
  80. String key = k;
  81. // a trailing ! indicates the the user expressed key!=value rather than key=value as a match constraint
  82. if (k.endsWith("!")) {
  83. key = key.substring(0, k.length() - 1);
  84. }
  85. String v = annotationValues.get(k);
  86. boolean validKey = false;
  87. for (int i = 0; i < ms.length; i++) {
  88. ResolvedMember resolvedMember = ms[i];
  89. if (resolvedMember.getName().equals(key) && resolvedMember.isAbstract()) {
  90. validKey = true;
  91. ResolvedType t = resolvedMember.getReturnType().resolve(scope.getWorld());
  92. if (t.isEnum()) {
  93. // value must be an enum reference X.Y
  94. int pos = v.lastIndexOf(".");
  95. if (pos == -1) {
  96. IMessage m = MessageUtil.error(
  97. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "enum"), getSourceLocation());
  98. scope.getWorld().getMessageHandler().handleMessage(m);
  99. } else {
  100. String typename = v.substring(0, pos);
  101. ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
  102. v = rt.getSignature() + v.substring(pos + 1); // from 'Color.RED' to 'Lp/Color;RED'
  103. replacementValues.put(k, v);
  104. break;
  105. }
  106. } else if (t.isPrimitiveType()) {
  107. if (t.getSignature().equals("I")) {
  108. try {
  109. int value = Integer.parseInt(v);
  110. replacementValues.put(k, Integer.toString(value));
  111. break;
  112. } catch (NumberFormatException nfe) {
  113. IMessage m = MessageUtil.error(
  114. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "int"),
  115. getSourceLocation());
  116. scope.getWorld().getMessageHandler().handleMessage(m);
  117. }
  118. } else if (t.getSignature().equals("F")) {
  119. try {
  120. float value = Float.parseFloat(v);
  121. replacementValues.put(k, Float.toString(value));
  122. break;
  123. } catch (NumberFormatException nfe) {
  124. IMessage m = MessageUtil.error(
  125. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "float"),
  126. getSourceLocation());
  127. scope.getWorld().getMessageHandler().handleMessage(m);
  128. }
  129. } else if (t.getSignature().equals("Z")) {
  130. if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("false")) {
  131. // is it ok !
  132. } else {
  133. IMessage m = MessageUtil.error(
  134. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "boolean"),
  135. getSourceLocation());
  136. scope.getWorld().getMessageHandler().handleMessage(m);
  137. }
  138. } else if (t.getSignature().equals("S")) {
  139. try {
  140. short value = Short.parseShort(v);
  141. replacementValues.put(k, Short.toString(value));
  142. break;
  143. } catch (NumberFormatException nfe) {
  144. IMessage m = MessageUtil.error(
  145. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "short"),
  146. getSourceLocation());
  147. scope.getWorld().getMessageHandler().handleMessage(m);
  148. }
  149. } else if (t.getSignature().equals("J")) {
  150. try {
  151. replacementValues.put(k, Long.toString(Long.parseLong(v)));
  152. break;
  153. } catch (NumberFormatException nfe) {
  154. IMessage m = MessageUtil.error(
  155. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "long"),
  156. getSourceLocation());
  157. scope.getWorld().getMessageHandler().handleMessage(m);
  158. }
  159. } else if (t.getSignature().equals("D")) {
  160. try {
  161. replacementValues.put(k, Double.toString(Double.parseDouble(v)));
  162. break;
  163. } catch (NumberFormatException nfe) {
  164. IMessage m = MessageUtil.error(
  165. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "double"),
  166. getSourceLocation());
  167. scope.getWorld().getMessageHandler().handleMessage(m);
  168. }
  169. } else if (t.getSignature().equals("B")) {
  170. try {
  171. replacementValues.put(k, Byte.toString(Byte.parseByte(v)));
  172. break;
  173. } catch (NumberFormatException nfe) {
  174. IMessage m = MessageUtil.error(
  175. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "byte"),
  176. getSourceLocation());
  177. scope.getWorld().getMessageHandler().handleMessage(m);
  178. }
  179. } else if (t.getSignature().equals("C")) {
  180. if (v.length() != 3) { // '?'
  181. IMessage m = MessageUtil.error(
  182. WeaverMessages.format(WeaverMessages.INVALID_ANNOTATION_VALUE, v, "char"),
  183. getSourceLocation());
  184. scope.getWorld().getMessageHandler().handleMessage(m);
  185. } else {
  186. replacementValues.put(k, v.substring(1, 2));
  187. break;
  188. }
  189. } else {
  190. throw new RuntimeException("Not implemented for " + t);
  191. }
  192. } else if (t.equals(ResolvedType.JL_STRING)) {
  193. // nothing to do, it will be OK
  194. } else if (t.equals(ResolvedType.JL_CLASS) || (t.isParameterizedOrGenericType() && t.getRawType().equals(ResolvedType.JL_CLASS))) {
  195. String typename = v.substring(0, v.lastIndexOf('.')); // strip off '.class'
  196. ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
  197. if (rt.isMissing()) {
  198. IMessage m = MessageUtil.error("Unable to resolve type '" + v + "' specified for value '" + k + "'",
  199. getSourceLocation());
  200. scope.getWorld().getMessageHandler().handleMessage(m);
  201. }
  202. replacementValues.put(k, rt.getSignature());
  203. break;
  204. } else {
  205. if (t.isAnnotation()) {
  206. if (v.indexOf("(") != -1) {
  207. throw new RuntimeException(
  208. "Compiler limitation: annotation values can only currently be marker annotations (no values): "
  209. + v);
  210. }
  211. String typename = v.substring(1);
  212. ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
  213. if (rt.isMissing()) {
  214. IMessage m = MessageUtil.error(
  215. "Unable to resolve type '" + v + "' specified for value '" + k + "'", getSourceLocation());
  216. scope.getWorld().getMessageHandler().handleMessage(m);
  217. }
  218. replacementValues.put(k, rt.getSignature());
  219. break;
  220. // } else if (t.isArray()) {
  221. // Looks like {} aren't pseudotokens in the parser so they don't get through for our pointcut parser
  222. // // @Foo(value=[Foo.class])
  223. // String typename = v.substring(0, v.lastIndexOf('.')); // strip off '.class'
  224. // ResolvedType rt = scope.lookupType(typename, this).resolve(scope.getWorld());
  225. // if (rt.isMissing()) {
  226. // IMessage m = MessageUtil.error("Unable to resolve type '" + v + "' specified for value '" + k + "'",
  227. // getSourceLocation());
  228. // scope.getWorld().getMessageHandler().handleMessage(m);
  229. // }
  230. // replacementValues.put(k, rt.getSignature());
  231. } else {
  232. scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.UNSUPPORTED_ANNOTATION_VALUE_TYPE,t), getSourceLocation()));
  233. replacementValues.put(k,"");
  234. }
  235. }
  236. }
  237. }
  238. if (!validKey) {
  239. IMessage m = MessageUtil.error(WeaverMessages.format(WeaverMessages.UNKNOWN_ANNOTATION_VALUE, annotationType, k),
  240. getSourceLocation());
  241. scope.getWorld().getMessageHandler().handleMessage(m);
  242. }
  243. }
  244. annotationValues.putAll(replacementValues);
  245. }
  246. @Override
  247. public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {
  248. if (!resolved) {
  249. throw new IllegalStateException("Can't match on an unresolved annotation type pattern");
  250. }
  251. if (annotationValues != null && !typePattern.hasFailedResolution()) {
  252. // PVAL improve this restriction, would allow '*(value=Color.RED)'
  253. throw new IllegalStateException("Cannot use annotationvalues with a wild annotation pattern");
  254. }
  255. if (isForParameterAnnotationMatch()) {
  256. if (parameterAnnotations != null && parameterAnnotations.length != 0) {
  257. for (int i = 0; i < parameterAnnotations.length; i++) {
  258. if (typePattern.matches(parameterAnnotations[i], TypePattern.STATIC).alwaysTrue()) {
  259. return FuzzyBoolean.YES;
  260. }
  261. }
  262. }
  263. } else {
  264. // matches if the type of any of the annotations on the AnnotatedElement is
  265. // matched by the typePattern.
  266. ResolvedType[] annTypes = annotated.getAnnotationTypes();
  267. if (annTypes != null && annTypes.length != 0) {
  268. for (int i = 0; i < annTypes.length; i++) {
  269. if (typePattern.matches(annTypes[i], TypePattern.STATIC).alwaysTrue()) {
  270. return FuzzyBoolean.YES;
  271. }
  272. }
  273. }
  274. }
  275. return FuzzyBoolean.NO;
  276. }
  277. /*
  278. * (non-Javadoc)
  279. *
  280. * @see org.aspectj.weaver.patterns.AnnotationTypePattern#resolve(org.aspectj.weaver.World)
  281. */
  282. @Override
  283. public void resolve(World world) {
  284. if (!resolved) {
  285. // attempt resolution - this helps with the Spring bug where they resolve() the pointcut in no scope (SPR-5307)
  286. if (typePattern instanceof WildTypePattern && (annotationValues == null || annotationValues.isEmpty())) {
  287. WildTypePattern wildTypePattern = (WildTypePattern) typePattern;
  288. String fullyQualifiedName = wildTypePattern.maybeGetCleanName();
  289. if (fullyQualifiedName != null && fullyQualifiedName.indexOf(".") != -1) {
  290. ResolvedType resolvedType = world.resolve(UnresolvedType.forName(fullyQualifiedName));
  291. if (resolvedType != null && !resolvedType.isMissing()) {
  292. typePattern = new ExactTypePattern(resolvedType, false, false);
  293. }
  294. }
  295. }
  296. resolved = true;
  297. }
  298. }
  299. /**
  300. * This can modify in place, or return a new TypePattern if the type changes.
  301. */
  302. @Override
  303. public AnnotationTypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) {
  304. if (!scope.getWorld().isInJava5Mode()) {
  305. scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ANNOTATIONS_NEED_JAVA5), getSourceLocation()));
  306. return this;
  307. }
  308. if (resolved) {
  309. return this;
  310. }
  311. this.typePattern = typePattern.resolveBindings(scope, bindings, false, false);
  312. resolved = true;
  313. if (typePattern instanceof ExactTypePattern) {
  314. ExactTypePattern et = (ExactTypePattern) typePattern;
  315. if (!et.getExactType().resolve(scope.getWorld()).isAnnotation()) {
  316. IMessage m = MessageUtil.error(
  317. WeaverMessages.format(WeaverMessages.REFERENCE_TO_NON_ANNOTATION_TYPE, et.getExactType().getName()),
  318. getSourceLocation());
  319. scope.getWorld().getMessageHandler().handleMessage(m);
  320. resolved = false;
  321. }
  322. ResolvedType annotationType = et.getExactType().resolve(scope.getWorld());
  323. resolveAnnotationValues(annotationType, scope);
  324. ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(annotationType, annotationValues);
  325. eatp.copyLocationFrom(this);
  326. if (isForParameterAnnotationMatch()) {
  327. eatp.setForParameterAnnotationMatch();
  328. }
  329. return eatp;
  330. } else {
  331. return this;
  332. }
  333. }
  334. @Override
  335. public AnnotationTypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
  336. WildAnnotationTypePattern ret = new WildAnnotationTypePattern(typePattern.parameterizeWith(typeVariableMap, w));
  337. ret.copyLocationFrom(this);
  338. ret.resolved = resolved;
  339. return ret;
  340. }
  341. private static final byte VERSION = 1; // rev if ser. form changes
  342. @Override
  343. public void write(CompressingDataOutputStream s) throws IOException {
  344. s.writeByte(AnnotationTypePattern.WILD);
  345. s.writeByte(VERSION);
  346. typePattern.write(s);
  347. writeLocation(s);
  348. s.writeBoolean(isForParameterAnnotationMatch());
  349. // PVAL
  350. if (annotationValues == null) {
  351. s.writeInt(0);
  352. } else {
  353. s.writeInt(annotationValues.size());
  354. Set<String> key = annotationValues.keySet();
  355. for (Iterator<String> keys = key.iterator(); keys.hasNext();) {
  356. String k = keys.next();
  357. s.writeUTF(k);
  358. s.writeUTF(annotationValues.get(k));
  359. }
  360. }
  361. }
  362. public static AnnotationTypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  363. WildAnnotationTypePattern ret;
  364. byte version = s.readByte();
  365. if (version > VERSION) {
  366. throw new BCException("ExactAnnotationTypePattern was written by a newer version of AspectJ");
  367. }
  368. TypePattern t = TypePattern.read(s, context);
  369. ret = new WildAnnotationTypePattern(t);
  370. ret.readLocation(context, s);
  371. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160) {
  372. if (s.readBoolean()) {
  373. ret.setForParameterAnnotationMatch();
  374. }
  375. }
  376. if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ160M2) {
  377. int annotationValueCount = s.readInt();
  378. if (annotationValueCount > 0) {
  379. Map<String, String> aValues = new HashMap<String, String>();
  380. for (int i = 0; i < annotationValueCount; i++) {
  381. String key = s.readUTF();
  382. String val = s.readUTF();
  383. aValues.put(key, val);
  384. }
  385. ret.annotationValues = aValues;
  386. }
  387. }
  388. return ret;
  389. }
  390. @Override
  391. public boolean equals(Object obj) {
  392. if (!(obj instanceof WildAnnotationTypePattern)) {
  393. return false;
  394. }
  395. WildAnnotationTypePattern other = (WildAnnotationTypePattern) obj;
  396. return other.typePattern.equals(typePattern)
  397. && this.isForParameterAnnotationMatch() == other.isForParameterAnnotationMatch()
  398. && (annotationValues == null ? other.annotationValues == null : annotationValues.equals(other.annotationValues));
  399. }
  400. @Override
  401. public int hashCode() {
  402. return (((17 + 37 * typePattern.hashCode()) * 37 + (isForParameterAnnotationMatch() ? 0 : 1)) * 37)
  403. + (annotationValues == null ? 0 : annotationValues.hashCode());
  404. }
  405. @Override
  406. public String toString() {
  407. return "@(" + typePattern.toString() + ")";
  408. }
  409. @Override
  410. public Object accept(PatternNodeVisitor visitor, Object data) {
  411. return visitor.visit(this, data);
  412. }
  413. }