From 096b004fda4d21cca0e1ee4c776e5824715d0ecd Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Mon, 2 Apr 2012 14:15:08 -0700 Subject: [PATCH] 375881 --- .../loadtime/ConcreteAspectCodeGen.java | 291 ++++++++++++++++++ .../weaver/patterns/BasicTokenSource.java | 2 +- tests/bugs170/xmldefs/Anno.class | Bin 0 -> 128 bytes tests/bugs170/xmldefs/Anno.java | 5 + tests/bugs170/xmldefs/Anno2.java | 5 + tests/bugs170/xmldefs/Anno4.java | 25 ++ tests/bugs170/xmldefs/Anno5.java | 37 +++ tests/bugs170/xmldefs/Anno6.java | 9 + tests/bugs170/xmldefs/AnnoBoolean.class | Bin 0 -> 220 bytes tests/bugs170/xmldefs/AnnoClass.class | Bin 0 -> 267 bytes tests/bugs170/xmldefs/AnnoLong.class | Bin 0 -> 225 bytes tests/bugs170/xmldefs/AnnoString.class | Bin 0 -> 238 bytes tests/bugs170/xmldefs/Foo.class | Bin 0 -> 2300 bytes tests/bugs170/xmldefs/Foo.java | 3 + tests/bugs170/xmldefs/Hello.java | 36 +++ tests/bugs170/xmldefs/Hello2.java | 27 ++ tests/bugs170/xmldefs/Hello4.java | 42 +++ tests/bugs170/xmldefs/Hello5.java | 42 +++ tests/bugs170/xmldefs/Hello6.java | 41 +++ tests/bugs170/xmldefs/aop.xml | 13 + tests/bugs170/xmldefs/aop2.xml | 13 + tests/bugs170/xmldefs/aop3.xml | 13 + tests/bugs170/xmldefs/aop4.xml | 17 + tests/bugs170/xmldefs/aop5.xml | 18 ++ tests/bugs170/xmldefs/aop6.xml | 13 + tests/bugs170/xmldefs/aop6a.xml | 13 + .../systemtest/ajc170/Ajc170Tests.java | 38 ++- .../org/aspectj/systemtest/ajc170/ajc170.xml | 100 ++++++ .../org/aspectj/weaver/bcel/LazyClassGen.java | 4 + .../loadtime/definition/Definition.java | 18 ++ .../loadtime/definition/DocumentParser.java | 27 ++ 31 files changed, 843 insertions(+), 9 deletions(-) create mode 100644 tests/bugs170/xmldefs/Anno.class create mode 100644 tests/bugs170/xmldefs/Anno.java create mode 100644 tests/bugs170/xmldefs/Anno2.java create mode 100644 tests/bugs170/xmldefs/Anno4.java create mode 100644 tests/bugs170/xmldefs/Anno5.java create mode 100644 tests/bugs170/xmldefs/Anno6.java create mode 100644 tests/bugs170/xmldefs/AnnoBoolean.class create mode 100644 tests/bugs170/xmldefs/AnnoClass.class create mode 100644 tests/bugs170/xmldefs/AnnoLong.class create mode 100644 tests/bugs170/xmldefs/AnnoString.class create mode 100644 tests/bugs170/xmldefs/Foo.class create mode 100644 tests/bugs170/xmldefs/Foo.java create mode 100644 tests/bugs170/xmldefs/Hello.java create mode 100644 tests/bugs170/xmldefs/Hello2.java create mode 100644 tests/bugs170/xmldefs/Hello4.java create mode 100644 tests/bugs170/xmldefs/Hello5.java create mode 100644 tests/bugs170/xmldefs/Hello6.java create mode 100644 tests/bugs170/xmldefs/aop.xml create mode 100644 tests/bugs170/xmldefs/aop2.xml create mode 100644 tests/bugs170/xmldefs/aop3.xml create mode 100644 tests/bugs170/xmldefs/aop4.xml create mode 100644 tests/bugs170/xmldefs/aop5.xml create mode 100644 tests/bugs170/xmldefs/aop6.xml create mode 100644 tests/bugs170/xmldefs/aop6a.xml diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java index bab276699..bc6695e3e 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java @@ -21,8 +21,10 @@ import java.util.List; import java.util.Map; import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.classfile.ConstantPool; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; +import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue; import org.aspectj.apache.bcel.classfile.annotation.ElementValue; import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; @@ -36,6 +38,7 @@ import org.aspectj.apache.bcel.generic.ObjectType; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.Message; +import org.aspectj.weaver.AjAttribute; import org.aspectj.weaver.AnnotationAJ; import org.aspectj.weaver.GeneratedReferenceTypeDelegate; import org.aspectj.weaver.ReferenceType; @@ -50,7 +53,14 @@ import org.aspectj.weaver.bcel.LazyClassGen; import org.aspectj.weaver.bcel.LazyMethodGen; import org.aspectj.weaver.loadtime.definition.Definition; import org.aspectj.weaver.loadtime.definition.Definition.AdviceKind; +import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotationKind; import org.aspectj.weaver.loadtime.definition.Definition.PointcutAndAdvice; +import org.aspectj.weaver.patterns.BasicTokenSource; +import org.aspectj.weaver.patterns.DeclareAnnotation; +import org.aspectj.weaver.patterns.ISignaturePattern; +import org.aspectj.weaver.patterns.ITokenSource; +import org.aspectj.weaver.patterns.NamePattern; +import org.aspectj.weaver.patterns.PatternParser; import org.aspectj.weaver.patterns.PerClause; import org.aspectj.weaver.patterns.PerSingleton; @@ -134,6 +144,11 @@ public class ConcreteAspectCodeGen { isValid = true; return true; } + + if (concreteAspect.declareAnnotations.size()!=0) { + isValid = true; + return true; + } // it can happen that extends is null, for precedence only declaration if (concreteAspect.extend == null && concreteAspect.precedence != null) { @@ -471,6 +486,13 @@ public class ConcreteAspectCodeGen { adviceCounter++; } } + + if (concreteAspect.declareAnnotations.size()>0) { + int decCounter = 1; + for (Definition.DeclareAnnotation da: concreteAspect.declareAnnotations) { + generateDeclareAnnotation(da,decCounter++,cg); + } + } // handle the perClause ReferenceType rt = new ReferenceType(ResolvedType.forName(concreteAspect.name).getSignature(), world); @@ -491,6 +513,275 @@ public class ConcreteAspectCodeGen { return bytes; } + /** + * The DeclareAnnotation object encapsulates an method/field/type descriptor and an annotation. This uses a DeclareAnnotation object + * captured from the XML (something like '') + * and builds the same construct that would have existed if the code style variant was used. This involves creating a member upon + * which to hang the real annotation and then creating a classfile level attribute indicating a declare annotation is present + * (that includes the signature pattern and a pointer to the real member holding the annotation). + * + */ + private void generateDeclareAnnotation(Definition.DeclareAnnotation da, int decCounter, LazyClassGen cg) { + + // Here is an example member from a code style declare annotation: + //void ajc$declare_at_method_1(); + // RuntimeInvisibleAnnotations: length = 0x6 + // 00 01 00 1B 00 00 + // RuntimeVisibleAnnotations: length = 0x15 + // 00 01 00 1D 00 03 00 1E 73 00 1F 00 20 73 00 21 + // 00 22 73 00 23 + // org.aspectj.weaver.MethodDeclarationLineNumber: length = 0x8 + // 00 00 00 02 00 00 00 16 + // org.aspectj.weaver.AjSynthetic: length = 0x + // + // Code: + // Stack=0, Locals=1, Args_size=1 + // 0: return + + // and at the class level a Declare attribute: + // org.aspectj.weaver.Declare: length = 0x51 + // 05 00 00 00 03 01 00 05 40 41 6E 6E 6F 01 00 17 + // 61 6A 63 24 64 65 63 6C 61 72 65 5F 61 74 5F 6D + // 65 74 68 6F 64 5F 31 01 01 00 00 00 00 05 05 00 + // 08 73 61 79 48 65 6C 6C 6F 00 01 04 00 00 00 00 + // 07 00 00 00 27 00 00 00 34 00 00 00 16 00 00 00 + // 3C + + AnnotationAJ constructedAnnotation = buildDeclareAnnotation_actualAnnotation(cg, da); + if (constructedAnnotation==null) { + return; // error occurred (and was reported), do not continue + } + if (da.declareAnnotationKind==DeclareAnnotationKind.Method || da.declareAnnotationKind==DeclareAnnotationKind.Field) { + String declareName = new StringBuilder("ajc$declare_at_").append(da.declareAnnotationKind==DeclareAnnotationKind.Method?"method":"field").append("_").append(decCounter).toString(); + LazyMethodGen declareMethod = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, declareName, Type.NO_ARGS, EMPTY_STRINGS, cg); + InstructionList declareMethodBody = declareMethod.getBody(); + declareMethodBody.append(InstructionFactory.RETURN); + declareMethod.addAnnotation(constructedAnnotation); + + ITokenSource tokenSource = BasicTokenSource.makeTokenSource(da.pattern,null); + PatternParser pp = new PatternParser(tokenSource); + ISignaturePattern isp = (da.declareAnnotationKind==DeclareAnnotationKind.Method?pp.parseCompoundMethodOrConstructorSignaturePattern(true):pp.parseCompoundFieldSignaturePattern()); + DeclareAnnotation deca = new DeclareAnnotation(da.declareAnnotationKind==DeclareAnnotationKind.Method?DeclareAnnotation.AT_METHOD:DeclareAnnotation.AT_FIELD, isp); + deca.setAnnotationMethod(declareName); + deca.setAnnotationString(da.annotation); + AjAttribute attribute = new AjAttribute.DeclareAttribute(deca); + cg.addAttribute(attribute); + cg.addMethodGen(declareMethod); + } + } + + /** + * Construct the annotation that the declare wants to add to the target. + */ + private AnnotationAJ buildDeclareAnnotation_actualAnnotation(LazyClassGen cg, Definition.DeclareAnnotation da) { + AnnotationGen anno = buildAnnotationFromString(cg.getConstantPool(),cg.getWorld(),da.annotation); + if (anno==null) { + return null; + } else { + AnnotationAJ bcelAnnotation = new BcelAnnotation(anno, world); + return bcelAnnotation; + } + } + + // TODO support array values + // TODO support annotation values + /** + * Build an AnnotationGen object based on a string, for example "@Foo(35,message='string')". Notice single quotes are fine for + * strings as they don't need special handling in the XML. + */ + private AnnotationGen buildAnnotationFromString(ConstantPool cp, World w, String annotationString) { + int paren = annotationString.indexOf('('); + if (paren==-1) { + // the easy case, no values + AnnotationGen aaj = buildBaseAnnotationType(cp,world,annotationString); + return aaj; + } else { + // Discover the name and name/value pairs + String name = annotationString.substring(0,paren); + // break the rest into pieces based on the commas + List values = new ArrayList(); + int pos = paren+1; + int depth = 0; + int len = annotationString.length(); + int start = pos; + while (pos elems = new ArrayList(); + return new AnnotationGen(new ObjectType(annoname), elems, true, cp); + } + + /** + * Construct the annotation that indicates this is a declare + */ + /** * The PointcutAndAdvice object encapsulates an advice kind, a pointcut and names a Java method in a particular class. Generate * an annotation style advice that has that pointcut whose implementation delegates to the Java method. diff --git a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BasicTokenSource.java b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BasicTokenSource.java index 37bc7eda1..9e2a62618 100644 --- a/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BasicTokenSource.java +++ b/org.aspectj.matcher/src/org/aspectj/weaver/patterns/BasicTokenSource.java @@ -80,7 +80,7 @@ public class BasicTokenSource implements ITokenSource { ////////////////////////////////////////////////////// // Convenience, maybe just for testing - static ITokenSource makeTokenSource(String input, ISourceContext context) { + public static ITokenSource makeTokenSource(String input, ISourceContext context) { char[] chars = input.toCharArray(); int i = 0; diff --git a/tests/bugs170/xmldefs/Anno.class b/tests/bugs170/xmldefs/Anno.class new file mode 100644 index 0000000000000000000000000000000000000000..6e378d76086f6fcd6baa6b269b1c56ade17af516 GIT binary patch literal 128 zcmX^0Z`VEs1_nb0PId++Mg|tgyu5sN1{OvJfvm)`ME#t^ymWp4q^#8B5_SeQMh1C= zXd+N$Nn%N6ex5!^6NJggz!jWdT9lmXmYI{v$iNAb(F5sGV`N}tUn9?)odRl literal 0 HcmV?d00001 diff --git a/tests/bugs170/xmldefs/Anno.java b/tests/bugs170/xmldefs/Anno.java new file mode 100644 index 000000000..7bb1cb2aa --- /dev/null +++ b/tests/bugs170/xmldefs/Anno.java @@ -0,0 +1,5 @@ +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Anno { +} diff --git a/tests/bugs170/xmldefs/Anno2.java b/tests/bugs170/xmldefs/Anno2.java new file mode 100644 index 000000000..f5dfcb99f --- /dev/null +++ b/tests/bugs170/xmldefs/Anno2.java @@ -0,0 +1,5 @@ +import java.lang.annotation.*; + +// deliberately wrong retention +public @interface Anno2 { +} diff --git a/tests/bugs170/xmldefs/Anno4.java b/tests/bugs170/xmldefs/Anno4.java new file mode 100644 index 000000000..ebff22092 --- /dev/null +++ b/tests/bugs170/xmldefs/Anno4.java @@ -0,0 +1,25 @@ +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoString { + String value() default "xyz"; + String sss() default "xyz"; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoLong { + long value() default 111L; + long jjj() default 111L; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoBoolean { + boolean value() default false; + boolean zzz() default false; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoClass { + Class value() default String.class; + Class ccc() default String.class; +} diff --git a/tests/bugs170/xmldefs/Anno5.java b/tests/bugs170/xmldefs/Anno5.java new file mode 100644 index 000000000..5906bcaa1 --- /dev/null +++ b/tests/bugs170/xmldefs/Anno5.java @@ -0,0 +1,37 @@ +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoShort { + short value() default 3; + short sss() default 3; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoDouble { + double value() default 3.0d; + double ddd() default 3.0d; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoFloat { + float value() default 4.0f; + float fff() default 4.0f; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoChar { + char value() default 'a'; + char ccc() default 'a'; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoByte { + byte value() default 66; + byte bbb() default 66; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface AnnoInt { + int value() default 111; + int iii() default 111; +} diff --git a/tests/bugs170/xmldefs/Anno6.java b/tests/bugs170/xmldefs/Anno6.java new file mode 100644 index 000000000..18d8f544b --- /dev/null +++ b/tests/bugs170/xmldefs/Anno6.java @@ -0,0 +1,9 @@ +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@interface Annot { + char a(); + boolean fred(); + String value(); +} + diff --git a/tests/bugs170/xmldefs/AnnoBoolean.class b/tests/bugs170/xmldefs/AnnoBoolean.class new file mode 100644 index 0000000000000000000000000000000000000000..33b76156ad98939817f592ad949f7bbed5c6bab8 GIT binary patch literal 220 zcmYk0I}XA?3`EByA&~Gr0Ud&dNN@rWqNSiqXQBlqTJ1_`lOji>-~b#7v2F;3CC{_R zU`9?O8egPUTE_na| literal 0 HcmV?d00001 diff --git a/tests/bugs170/xmldefs/AnnoClass.class b/tests/bugs170/xmldefs/AnnoClass.class new file mode 100644 index 0000000000000000000000000000000000000000..4071d56d653bac83ecbb5c384ed570a15d1568aa GIT binary patch literal 267 zcmYk1I|{-;5QhIXiEH9p4`3(S7|_y66hROya)NbPL&CCwWRt^LcmNM2PAp7{DgFoZ z&AdO)7l19s90QIa$B4nJgf11se6_x&q7tDNCJv8U6vduldN3xl!X}wHsfQ@FWtg>k zkMYr!0uFGMDO{XyOF*#@(hyG5EFku^1)|{dP~4B+{a>#Q%=4 gIcW(nbZ8uUtK%}b@JMw@ITD1PMTH`!sV(UWIJnJBb(aUy}HWQG%+Xq-1$Xo{Y6Je&aSQEbwCqB4cYuQP{(8JN$ijaDf8)>WjbkVA82=iXaUt8W6F91To8**(B5hBD)1E#Qm OU@`g^3E#&46O#`kEiK^y literal 0 HcmV?d00001 diff --git a/tests/bugs170/xmldefs/AnnoString.class b/tests/bugs170/xmldefs/AnnoString.class new file mode 100644 index 0000000000000000000000000000000000000000..ba0e8eaf7cb9aa206a9fe0ceacd0d5d68e4fecb0 GIT binary patch literal 238 zcmX^0Z`VEs1_mPres%^Pb_QN{20lgx*0RK$(o{wU5e-eBti-ZJ{hY+Sbp7CxqRhN> zYeoh^$Gp7!lEjkC{5+S`w8YY!5=I8*#H3^(SzKHUBr7Vb7#X;N^Gl18Q{6IifF^N) zv>5Aw41;nYrZF-IAT01t%1TWJnkA1AN`%{_kFZpYfq{{M35c12E@xt4WME-n1@hQ{ WJmz8scAx+UvH&Mgjtiucfg1qXq&GDH literal 0 HcmV?d00001 diff --git a/tests/bugs170/xmldefs/Foo.class b/tests/bugs170/xmldefs/Foo.class new file mode 100644 index 0000000000000000000000000000000000000000..eaa12c965535241adafa9cc6f28db121ffff29aa GIT binary patch literal 2300 zcmeHHO>Y}T7=FgzHl{IYlQb=q0D(A8@HP+{AQ2D(5f!EtxCE6;n5?Jvn)Pn9yH3*s zXMPHo9%y?AY9+W)i93G>cxKkgI?_fUP8?WiW_I3rKcDxR`R$L#KLc37MiCi-?6&V0 zkrSx(<$<(Z>2s}a1&!$Pf#V}MUZP>1M_#Ok-7k315TYg7XAnxiNLbh~p)1H@riv*YEf@8i zP+&#}?I_!of!dYP?m$I7zq7j{aQTa&7dZoU-8*nXhrTvF&yQr}_#W*FExl!3vm>>g z6s7f+A9O7l?i16#<#>?_Jn6e!@ySCjwV8hylZOG2+W`AgUKlY(25-q z@JlJhj~XK|mvZ=(L3Bq2A?qO(QdEw!Of!$O-SWwcL*BXftuI5mvZU>*f$}1&>qMb7 z=F^H)NXg!?8?LNfwGIbvN8Jgnq|UVN#W}V~T!ohiQK-@mU8;?*=uSf?k8l*I8Z*ljg3A2i8 zTtClq$|g_4nXjD24Ea1t$L|Y-L83_U0>>)HG{*+kIO|K!Ph4Am{PY{V&EK;4bM)aI zqwp^0ETL+!kac48eVYRPWxmt$t M`W}<=KSRd90D_~lBLDyZ literal 0 HcmV?d00001 diff --git a/tests/bugs170/xmldefs/Foo.java b/tests/bugs170/xmldefs/Foo.java new file mode 100644 index 000000000..2edbdabfd --- /dev/null +++ b/tests/bugs170/xmldefs/Foo.java @@ -0,0 +1,3 @@ +public aspect Foo { + declare @method: * sayHello(..): @Anno; +} diff --git a/tests/bugs170/xmldefs/Hello.java b/tests/bugs170/xmldefs/Hello.java new file mode 100644 index 000000000..fdf29eab3 --- /dev/null +++ b/tests/bugs170/xmldefs/Hello.java @@ -0,0 +1,36 @@ +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +public class Hello { + + public static void main(String[] args) { + sayHello(); + printAnnos("sayHello"); + } + + public static void sayHello() { + System.out.println("Hello"); + sayWorld(); + } + + public static int sayWorld() { + System.out.println("World"); + return 0; + } + + public static void printAnnos(String methodname) { + try { + Method m = Hello.class.getDeclaredMethod(methodname); + Annotation[] annos = m.getAnnotations(); + System.out.println("Annotations on "+methodname+"? "+(annos!=null && annos.length!=0)); + if (annos!=null && annos.length>0) { + System.out.println("Annotation count is "+annos.length); + for (Annotation anno: annos) { + System.out.println(anno); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/tests/bugs170/xmldefs/Hello2.java b/tests/bugs170/xmldefs/Hello2.java new file mode 100644 index 000000000..9fa6a4a9a --- /dev/null +++ b/tests/bugs170/xmldefs/Hello2.java @@ -0,0 +1,27 @@ +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +public class Hello2 { + + public static int i; + + public static void main(String[] args) { + printAnnos("i"); + } + + public static void printAnnos(String fieldname) { + try { + Field m = Hello2.class.getDeclaredField(fieldname); + Annotation[] annos = m.getAnnotations(); + System.out.println("Annotations on "+fieldname+"? "+(annos!=null && annos.length!=0)); + if (annos!=null && annos.length>0) { + System.out.println("Annotation count is "+annos.length); + for (Annotation anno: annos) { + System.out.println(anno); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/tests/bugs170/xmldefs/Hello4.java b/tests/bugs170/xmldefs/Hello4.java new file mode 100644 index 000000000..7f7c6183b --- /dev/null +++ b/tests/bugs170/xmldefs/Hello4.java @@ -0,0 +1,42 @@ +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.*; +public class Hello4 { + + public static int field1; + public static int field2; + + public static void main(String[] args) { + printAnnos("field1"); + printAnnos("field2"); + } + + public static void printAnnos(String fieldname) { + try { + Field m = Hello4.class.getDeclaredField(fieldname); + Annotation[] annos = m.getAnnotations(); + System.out.println("Annotations on "+fieldname+"? "+(annos!=null && annos.length!=0)); + if (annos!=null && annos.length>0) { + List la = new ArrayList(); + for (Annotation anno: annos) { + la.add(anno); + } + Collections.sort(la,new AnnoComparator()); + + System.out.println("Annotation count is "+annos.length); + for (Annotation anno: la) { + System.out.println(anno); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static class AnnoComparator implements Comparator { + public int compare(Annotation a, Annotation b) { + return a.toString().compareTo(b.toString()); + } + } +} diff --git a/tests/bugs170/xmldefs/Hello5.java b/tests/bugs170/xmldefs/Hello5.java new file mode 100644 index 000000000..361415a3e --- /dev/null +++ b/tests/bugs170/xmldefs/Hello5.java @@ -0,0 +1,42 @@ +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.*; +public class Hello5 { + + public static int field1; + public static int field2; + + public static void main(String[] args) { + printAnnos("field1"); + printAnnos("field2"); + } + + public static void printAnnos(String fieldname) { + try { + Field m = Hello5.class.getDeclaredField(fieldname); + Annotation[] annos = m.getAnnotations(); + System.out.println("Annotations on "+fieldname+"? "+(annos!=null && annos.length!=0)); + if (annos!=null && annos.length>0) { + List la = new ArrayList(); + for (Annotation anno: annos) { + la.add(anno); + } + Collections.sort(la,new AnnoComparator()); + + System.out.println("Annotation count is "+annos.length); + for (Annotation anno: la) { + System.out.println(anno); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static class AnnoComparator implements Comparator { + public int compare(Annotation a, Annotation b) { + return a.toString().compareTo(b.toString()); + } + } +} diff --git a/tests/bugs170/xmldefs/Hello6.java b/tests/bugs170/xmldefs/Hello6.java new file mode 100644 index 000000000..568a5b46e --- /dev/null +++ b/tests/bugs170/xmldefs/Hello6.java @@ -0,0 +1,41 @@ +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.*; + +public class Hello6 { + + public static int field1; + + public static void main(String[] args) { + printAnnos("field1"); + } + + public static void printAnnos(String fieldname) { + try { + Field m = Hello6.class.getDeclaredField(fieldname); + Annotation[] annos = m.getAnnotations(); + System.out.println("Annotations on "+fieldname+"? "+(annos!=null && annos.length!=0)); + if (annos!=null && annos.length>0) { + List la = new ArrayList(); + for (Annotation anno: annos) { + la.add(anno); + } + Collections.sort(la,new AnnoComparator()); + + System.out.println("Annotation count is "+annos.length); + for (Annotation anno: la) { + System.out.println(anno); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + static class AnnoComparator implements Comparator { + public int compare(Annotation a, Annotation b) { + return a.toString().compareTo(b.toString()); + } + } +} diff --git a/tests/bugs170/xmldefs/aop.xml b/tests/bugs170/xmldefs/aop.xml new file mode 100644 index 000000000..afa85168b --- /dev/null +++ b/tests/bugs170/xmldefs/aop.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop2.xml b/tests/bugs170/xmldefs/aop2.xml new file mode 100644 index 000000000..d5ebdf7af --- /dev/null +++ b/tests/bugs170/xmldefs/aop2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop3.xml b/tests/bugs170/xmldefs/aop3.xml new file mode 100644 index 000000000..a65a552ed --- /dev/null +++ b/tests/bugs170/xmldefs/aop3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop4.xml b/tests/bugs170/xmldefs/aop4.xml new file mode 100644 index 000000000..1cf61807b --- /dev/null +++ b/tests/bugs170/xmldefs/aop4.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop5.xml b/tests/bugs170/xmldefs/aop5.xml new file mode 100644 index 000000000..31a5f7d48 --- /dev/null +++ b/tests/bugs170/xmldefs/aop5.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop6.xml b/tests/bugs170/xmldefs/aop6.xml new file mode 100644 index 000000000..06300b72f --- /dev/null +++ b/tests/bugs170/xmldefs/aop6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/bugs170/xmldefs/aop6a.xml b/tests/bugs170/xmldefs/aop6a.xml new file mode 100644 index 000000000..2c6410a9b --- /dev/null +++ b/tests/bugs170/xmldefs/aop6a.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/src/org/aspectj/systemtest/ajc170/Ajc170Tests.java b/tests/src/org/aspectj/systemtest/ajc170/Ajc170Tests.java index 9ce29a36f..907464990 100644 --- a/tests/src/org/aspectj/systemtest/ajc170/Ajc170Tests.java +++ b/tests/src/org/aspectj/systemtest/ajc170/Ajc170Tests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Contributors + * Copyright (c) 2008-2012 Contributors * 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 @@ -17,20 +17,13 @@ import junit.framework.Test; import org.aspectj.apache.bcel.classfile.Field; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.testing.XMLBasedAjcTestCase; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.TypeFactory; import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.World; import org.aspectj.weaver.internal.tools.StandardPointcutExpressionImpl; -import org.aspectj.weaver.patterns.BasicTokenSource; -import org.aspectj.weaver.patterns.ITokenSource; -import org.aspectj.weaver.patterns.PatternParser; import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.PointcutEvaluationExpenseComparator; import org.aspectj.weaver.patterns.PointcutRewriter; import org.aspectj.weaver.reflect.ReflectionWorld; -import org.aspectj.weaver.tools.StandardPointcutExpression; import org.aspectj.weaver.tools.StandardPointcutParser; /** @@ -38,6 +31,35 @@ import org.aspectj.weaver.tools.StandardPointcutParser; */ public class Ajc170Tests extends org.aspectj.testing.XMLBasedAjcTestCase { + public void testXmlDefsDeclareAnnoMethod() { + runTest("xml defined dec at method"); + } + + // anno not runtime vis + public void testXmlDefsDeclareAnnoMethod2() { + runTest("xml defined dec at method 2"); + } + + public void testXmlDefsDeclareAnnoField() { + runTest("xml defined dec at field"); + } + + public void testXmlDefsDeclareAnnoFieldVariants1() { + runTest("xml defined dec anno - variants 1"); + } + + public void testXmlDefsDeclareAnnoFieldVariants2() { + runTest("xml defined dec anno - variants 2"); + } + + public void testXmlDefsDeclareAnnoFieldMultipleValues() { + runTest("xml defined dec anno - multiple values"); + } + + public void testXmlDefsDeclareAnnoFieldMultipleValuesAndSpaces() { + runTest("xml defined dec anno - multiple values and spaces"); + } + public void testPointcutExpense_374964() { // check a declaring type being specified causes the call() to be considered cheaper than this() diff --git a/tests/src/org/aspectj/systemtest/ajc170/ajc170.xml b/tests/src/org/aspectj/systemtest/ajc170/ajc170.xml index 58c936905..daed3a8e7 100644 --- a/tests/src/org/aspectj/systemtest/ajc170/ajc170.xml +++ b/tests/src/org/aspectj/systemtest/ajc170/ajc170.xml @@ -2,6 +2,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index d8a9c0e0e..62ebac92c 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -1578,6 +1578,10 @@ public final class LazyClassGen { annotations.add(new AnnotationGen(a, getConstantPool(), true)); } } + + public void addAttribute(AjAttribute attribute) { + myGen.addAttribute(Utility.bcelAttribute(attribute, getConstantPool())); + } // this test is like asking: // if diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java b/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java index 7f9ce729d..de780156e 100644 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java +++ b/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java @@ -112,6 +112,7 @@ public class Definition { public final String extend; public final String precedence; public final List pointcuts; + public final List declareAnnotations; public final List pointcutsAndAdvice; public final String perclause; public List deows; @@ -135,6 +136,7 @@ public class Definition { } this.precedence = precedence; this.pointcuts = new ArrayList(); + this.declareAnnotations = new ArrayList(); this.pointcutsAndAdvice = new ArrayList(); this.deows = new ArrayList(); this.perclause = perclause; @@ -154,6 +156,22 @@ public class Definition { public enum AdviceKind { Before, After, AfterReturning, AfterThrowing, Around; } + + public enum DeclareAnnotationKind { + Method, Field, Type; + } + + public static class DeclareAnnotation { + public final DeclareAnnotationKind declareAnnotationKind; + public final String pattern; + public final String annotation; + + public DeclareAnnotation(DeclareAnnotationKind kind, String pattern, String annotation) { + this.declareAnnotationKind = kind; + this.pattern = pattern; + this.annotation = annotation; + } + } public static class PointcutAndAdvice { public final AdviceKind adviceKind; diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java b/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java index 13968a696..7ff275fd7 100644 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java +++ b/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java @@ -22,6 +22,8 @@ import javax.xml.parsers.SAXParserFactory; import org.aspectj.util.LangUtil; import org.aspectj.weaver.loadtime.definition.Definition.AdviceKind; +import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotation; +import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotationKind; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -72,6 +74,7 @@ public class DocumentParser extends DefaultHandler { private final static String AROUND_ELEMENT = "around"; private final static String WITHIN_ATTRIBUTE = "within"; private final static String EXPRESSION_ATTRIBUTE = "expression"; + private final static String DECLARE_ANNOTATION_ELEMENT = "declare-annotation"; private final Definition definition; @@ -226,6 +229,30 @@ public class DocumentParser extends DefaultHandler { if (!isNull(name) && !isNull(expression)) { activeConcreteAspectDefinition.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); } + } else if (DECLARE_ANNOTATION_ELEMENT.equals(qName) && activeConcreteAspectDefinition!=null) { + String methodSig = attributes.getValue("method"); + String fieldSig = attributes.getValue("field"); + String typePat = attributes.getValue("type"); + String anno = attributes.getValue("annotation"); + if (isNull(anno)) { + throw new SAXException("Badly formed element, 'annotation' value is missing"); + } + if (isNull(methodSig) && isNull(fieldSig) && isNull(typePat)) { + throw new SAXException("Badly formed element, need one of 'method'/'field'/'type' specified"); + } + if (!isNull(methodSig)) { + // declare @method + activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Method, + methodSig, anno)); + } else if (!isNull(fieldSig)) { + // declare @field + activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Field, + fieldSig, anno)); + } else if (!isNull(typePat)) { + // declare @type + activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Type, + typePat, anno)); + } } else if (BEFORE_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) { String pointcut = attributes.getValue(POINTCUT_ELEMENT); String adviceClass = attributes.getValue("invokeClass"); -- 2.39.5