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.

AnnotationPointcut.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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.ArrayList;
  13. import java.util.Collections;
  14. import java.util.Iterator;
  15. import java.util.List;
  16. import java.util.Map;
  17. import org.aspectj.bridge.MessageUtil;
  18. import org.aspectj.util.FuzzyBoolean;
  19. import org.aspectj.weaver.AjcMemberMaker;
  20. import org.aspectj.weaver.AnnotatedElement;
  21. import org.aspectj.weaver.BCException;
  22. import org.aspectj.weaver.CompressingDataOutputStream;
  23. import org.aspectj.weaver.ConcreteTypeMunger;
  24. import org.aspectj.weaver.ISourceContext;
  25. import org.aspectj.weaver.IntMap;
  26. import org.aspectj.weaver.Member;
  27. import org.aspectj.weaver.NameMangler;
  28. import org.aspectj.weaver.NewFieldTypeMunger;
  29. import org.aspectj.weaver.ResolvedMember;
  30. import org.aspectj.weaver.ResolvedType;
  31. import org.aspectj.weaver.Shadow;
  32. import org.aspectj.weaver.ShadowMunger;
  33. import org.aspectj.weaver.UnresolvedType;
  34. import org.aspectj.weaver.VersionedDataInputStream;
  35. import org.aspectj.weaver.WeaverMessages;
  36. import org.aspectj.weaver.World;
  37. import org.aspectj.weaver.ast.Literal;
  38. import org.aspectj.weaver.ast.Test;
  39. import org.aspectj.weaver.ast.Var;
  40. /**
  41. * (at)Annotation((at)Foo) or (at)Annotation(foo)<br>
  42. * <p>
  43. * Matches any join point where the subject of the join point has an annotation matching the annotationTypePattern:
  44. *
  45. * <br>
  46. * Join Point Kind - Subject <br>
  47. * ================================ <br>
  48. * method call - the target method <br>
  49. * method execution - the method <br>
  50. * constructor call - the constructor <br>
  51. * constructor execution - the constructor <br>
  52. * get - the target field <br>
  53. * set - the target field <br>
  54. * adviceexecution - the advice <br>
  55. * initialization - the constructor <br>
  56. * preinitialization - the constructor <br>
  57. * staticinitialization - the type being initialized <br>
  58. * handler - the declared type of the handled exception <br>
  59. */
  60. public class AnnotationPointcut extends NameBindingPointcut {
  61. private ExactAnnotationTypePattern annotationTypePattern;
  62. private String declarationText;
  63. public AnnotationPointcut(ExactAnnotationTypePattern type) {
  64. super();
  65. this.annotationTypePattern = type;
  66. this.pointcutKind = Pointcut.ANNOTATION;
  67. buildDeclarationText();
  68. }
  69. public AnnotationPointcut(ExactAnnotationTypePattern type, ShadowMunger munger) {
  70. this(type);
  71. buildDeclarationText();
  72. }
  73. public ExactAnnotationTypePattern getAnnotationTypePattern() {
  74. return annotationTypePattern;
  75. }
  76. @Override
  77. public int couldMatchKinds() {
  78. return Shadow.ALL_SHADOW_KINDS_BITS;
  79. }
  80. @Override
  81. public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
  82. AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) annotationTypePattern.parameterizeWith(
  83. typeVariableMap, w));
  84. ret.copyLocationFrom(this);
  85. return ret;
  86. }
  87. /*
  88. * (non-Javadoc)
  89. *
  90. * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
  91. */
  92. @Override
  93. public FuzzyBoolean fastMatch(FastMatchInfo info) {
  94. if (info.getKind() == Shadow.StaticInitialization) {
  95. return annotationTypePattern.fastMatches(info.getType());
  96. } else {
  97. return FuzzyBoolean.MAYBE;
  98. }
  99. }
  100. /*
  101. * (non-Javadoc)
  102. *
  103. * @see org.aspectj.weaver.patterns.Pointcut#match(org.aspectj.weaver.Shadow)
  104. */
  105. @Override
  106. protected FuzzyBoolean matchInternal(Shadow shadow) {
  107. AnnotatedElement toMatchAgainst = null;
  108. Member member = shadow.getSignature();
  109. ResolvedMember rMember = member.resolve(shadow.getIWorld());
  110. if (rMember == null) {
  111. if (member.getName().startsWith(NameMangler.PREFIX)) {
  112. return FuzzyBoolean.NO;
  113. }
  114. shadow.getIWorld().getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
  115. return FuzzyBoolean.NO;
  116. }
  117. Shadow.Kind kind = shadow.getKind();
  118. if (kind == Shadow.StaticInitialization) {
  119. toMatchAgainst = rMember.getDeclaringType().resolve(shadow.getIWorld());
  120. } else if ((kind == Shadow.ExceptionHandler)) {
  121. toMatchAgainst = rMember.getParameterTypes()[0].resolve(shadow.getIWorld());
  122. } else {
  123. toMatchAgainst = rMember;
  124. // FIXME asc I'd like to get rid of this bit of logic altogether, shame ITD fields don't have an effective sig attribute
  125. // FIXME asc perf cache the result of discovering the member that contains the real annotations
  126. if (rMember.isAnnotatedElsewhere()) {
  127. if (kind == Shadow.FieldGet || kind == Shadow.FieldSet) {
  128. // FIXME asc should include supers with getInterTypeMungersIncludingSupers ?
  129. List mungers = rMember.getDeclaringType().resolve(shadow.getIWorld()).getInterTypeMungers();
  130. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  131. ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) iter.next();
  132. if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
  133. ResolvedMember fakerm = typeMunger.getSignature();
  134. if (fakerm.equals(member)) {
  135. ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
  136. ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
  137. toMatchAgainst = rmm;
  138. }
  139. }
  140. }
  141. }
  142. }
  143. }
  144. annotationTypePattern.resolve(shadow.getIWorld());
  145. return annotationTypePattern.matches(toMatchAgainst);
  146. }
  147. private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
  148. ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
  149. for (int i = 0; i < decMethods.length; i++) {
  150. ResolvedMember member = decMethods[i];
  151. if (member.equals(ajcMethod)) {
  152. return member;
  153. }
  154. }
  155. return null;
  156. }
  157. /*
  158. * (non-Javadoc)
  159. *
  160. * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope,
  161. * org.aspectj.weaver.patterns.Bindings)
  162. */
  163. @Override
  164. protected void resolveBindings(IScope scope, Bindings bindings) {
  165. if (!scope.getWorld().isInJava5Mode()) {
  166. scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.ATANNOTATION_ONLY_SUPPORTED_AT_JAVA5_LEVEL),
  167. getSourceLocation()));
  168. return;
  169. }
  170. annotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern.resolveBindings(scope, bindings, true);
  171. // must be either a Var, or an annotation type pattern
  172. }
  173. /*
  174. * (non-Javadoc)
  175. *
  176. * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
  177. */
  178. @Override
  179. protected Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
  180. ExactAnnotationTypePattern newType = (ExactAnnotationTypePattern) annotationTypePattern.remapAdviceFormals(bindings);
  181. Pointcut ret = new AnnotationPointcut(newType, bindings.getEnclosingAdvice());
  182. ret.copyLocationFrom(this);
  183. return ret;
  184. }
  185. @Override
  186. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  187. if (annotationTypePattern instanceof BindingAnnotationFieldTypePattern) {
  188. if (shadow.getKind() != Shadow.MethodExecution) {
  189. shadow.getIWorld()
  190. .getMessageHandler()
  191. .handleMessage(
  192. MessageUtil
  193. .error("Annotation field binding is only supported at method-execution join points (compiler limitation)",
  194. getSourceLocation()));
  195. return Literal.TRUE; // exit quickly, error will prevent weaving
  196. }
  197. BindingAnnotationFieldTypePattern btp = (BindingAnnotationFieldTypePattern) annotationTypePattern;
  198. ResolvedType formalType = btp.getFormalType().resolve(shadow.getIWorld());
  199. UnresolvedType annoType = btp.getAnnotationType();
  200. // TODO 2 need to sort out appropriate creation of the AnnotationAccessFieldVar - what happens for
  201. // reflective (ReflectionShadow) access to types?
  202. Var var = shadow.getKindedAnnotationVar(annoType);
  203. if (var == null) {
  204. throw new BCException("Unexpected problem locating annotation at join point '" + shadow + "'");
  205. }
  206. state.set(btp.getFormalIndex(), var.getAccessorForValue(formalType, btp.formalName));
  207. } else if (annotationTypePattern instanceof BindingAnnotationTypePattern) {
  208. BindingAnnotationTypePattern btp = (BindingAnnotationTypePattern) annotationTypePattern;
  209. UnresolvedType annotationType = btp.getAnnotationType();
  210. Var var = shadow.getKindedAnnotationVar(annotationType);
  211. // At this point, var *could* be null. The only reason this could happen (if we aren't failing...)
  212. // is if another binding annotation designator elsewhere in the pointcut is going to expose the annotation
  213. // eg. (execution(* a*(..)) && @annotation(foo)) || (execution(* b*(..)) && @this(foo))
  214. // where sometimes @annotation will be providing the value, and sometimes
  215. // @this will be providing the value (see pr138223)
  216. // If we are here for other indecipherable reasons (it's not the case above...) then
  217. // you might want to uncomment this next bit of code to collect the diagnostics
  218. // if (var == null) throw new BCException("Impossible! annotation=["+annotationType+
  219. // "] shadow=["+shadow+" at "+shadow.getSourceLocation()+
  220. // "] pointcut is at ["+getSourceLocation()+"]");
  221. if (var == null) {
  222. if (matchInternal(shadow).alwaysTrue()) {
  223. return Literal.TRUE;
  224. } else {
  225. return Literal.FALSE;
  226. }
  227. }
  228. state.set(btp.getFormalIndex(), var);
  229. }
  230. if (matchInternal(shadow).alwaysTrue()) {
  231. return Literal.TRUE;
  232. } else {
  233. return Literal.FALSE;
  234. }
  235. }
  236. /*
  237. * (non-Javadoc)
  238. *
  239. * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingAnnotationTypePatterns()
  240. */
  241. @Override
  242. public List<BindingPattern> getBindingAnnotationTypePatterns() {
  243. if (annotationTypePattern instanceof BindingPattern) { // BindingAnnotationTypePattern) {
  244. List<BindingPattern> l = new ArrayList<BindingPattern>();
  245. l.add((BindingPattern)annotationTypePattern);
  246. return l;
  247. } else {
  248. return Collections.emptyList();
  249. }
  250. }
  251. /*
  252. * (non-Javadoc)
  253. *
  254. * @see org.aspectj.weaver.patterns.NameBindingPointcut#getBindingTypePatterns()
  255. */
  256. @Override
  257. public List<BindingTypePattern> getBindingTypePatterns() {
  258. return Collections.emptyList();
  259. }
  260. /*
  261. * (non-Javadoc)
  262. *
  263. * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
  264. */
  265. @Override
  266. public void write(CompressingDataOutputStream s) throws IOException {
  267. s.writeByte(Pointcut.ANNOTATION);
  268. annotationTypePattern.write(s);
  269. writeLocation(s);
  270. }
  271. public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  272. AnnotationTypePattern type = AnnotationTypePattern.read(s, context);
  273. AnnotationPointcut ret = new AnnotationPointcut((ExactAnnotationTypePattern) type);
  274. ret.readLocation(context, s);
  275. return ret;
  276. }
  277. @Override
  278. public boolean equals(Object other) {
  279. if (!(other instanceof AnnotationPointcut)) {
  280. return false;
  281. }
  282. AnnotationPointcut o = (AnnotationPointcut) other;
  283. return o.annotationTypePattern.equals(this.annotationTypePattern);
  284. }
  285. @Override
  286. public int hashCode() {
  287. int result = 17;
  288. result = 37 * result + annotationTypePattern.hashCode();
  289. return result;
  290. }
  291. public void buildDeclarationText() {
  292. StringBuffer buf = new StringBuffer();
  293. buf.append("@annotation(");
  294. String annPatt = annotationTypePattern.toString();
  295. buf.append(annPatt.startsWith("@") ? annPatt.substring(1) : annPatt);
  296. buf.append(")");
  297. this.declarationText = buf.toString();
  298. }
  299. @Override
  300. public String toString() {
  301. return this.declarationText;
  302. }
  303. @Override
  304. public Object accept(PatternNodeVisitor visitor, Object data) {
  305. return visitor.visit(this, data);
  306. }
  307. }