Bug 445712 - No support for @Repeatable annotations
Summary: No support for @Repeatable annotations
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.8.3   Edit
Hardware: Macintosh Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-01 15:37 EDT by Johan Fabry CLA
Modified: 2014-10-01 19:30 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Johan Fabry CLA 2014-10-01 15:37:29 EDT
I’m experimenting with the @Repeatable annotations of Java 8 on some aspects, and apparently AspectJ does not provide any support for @Repeatable, as I get an exception at some point.

AspectJ Compiler version: 1.8.3.20140820082000	

Relevant stack trace (cutting out a ton of frames at the bottom as I’m doing the experiments in Clojure):

---

ERROR in (test-suite test-annotation-contents) (EclipseSourceType.java:820)
Uncaught exception, not in assertion.
expected: nil
 actual: org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType$MissingImplementationException: Please raise an AspectJ bug.  AspectJ does not know how to convert this annotation [@Repeatable(MultiRequires.class)]
at org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType.generateAnnotation (EclipseSourceType.java:820)
   org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType.convertEclipseAnnotation (EclipseSourceType.java:718)
   org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType.getAnnotations (EclipseSourceType.java:698)
   org.aspectj.weaver.ReferenceType.getAnnotations (ReferenceType.java:200)
   sun.reflect.NativeMethodAccessorImpl.invoke0 (NativeMethodAccessorImpl.java:-2)
   sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57)
   sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
   java.lang.reflect.Method.invoke (Method.java:606)
   clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:93)
   clojure.lang.Reflector.invokeNoArgInstanceMember (Reflector.java:313)

---

Source code of the annotation:

---
package damp.ekeko.aspectj.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Repeatable(MultiRequires.class)
public @interface Requires {
		
	String aspect() default "";
	String label() default "";
	
}

---

package damp.ekeko.aspectj.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
public @interface MultiRequires {
	Requires[] value(); 
}

---
Comment 1 Andrew Clement CLA 2014-10-01 15:45:07 EDT
I'm finding this works perfectly for me, so I suspect there is more to the situation that in your bug report. If I have this:
===
package pkg;

@Requires(aspect="A",label="B")
@Requires(aspect="C",label="D")
public class Code {
}
===
package pkg;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
public @interface MultiRequires {
        Requires[] value();
}
===
package pkg;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Repeatable(MultiRequires.class)
public @interface Requires {

        String aspect() default "";
        String label() default "";

}
===

and compile it, I get as expected. There is an instance of the MultiRequires annotation in the byte code for Code.class.

I don't deny there is a problem but we need to work out precisely the trigger. The code above confirms what I expected, that the basic support is being inherited from the JDT compiler just fine. Have you aspects in the mix utilizing these annotations?
Comment 2 Johan Fabry CLA 2014-10-01 15:53:50 EDT
Sorry for not being clear enough on what I'm doing! I'm reflectively inspecting the annotations after they have been compiled (using Clojure). This is why there is the java.lang.reflect.Method.invoke frame in the stack trace.

I don't have easy example code in Java at hand since I'm doing this from within Clojure and I can't recreate it in Java right now (I'm away from the office). If you need more concrete Java code I can try to reproduce using only Java tomorrow.
Comment 3 Andrew Clement CLA 2014-10-01 16:17:04 EDT
Are you load time weaving? I assumed not because of EclipseSourceType being on the stack trace.  I do see the method.invoke() and clojure further up the stack but how are they running - are they being invoked as part of the compilation process?

If I did straight reflection on the compiled class with annotations on it I wouldn't expect to see any mention of aspectj types (like org.aspectj.weaver.ReferenceType)
Comment 4 Johan Fabry CLA 2014-10-01 16:50:16 EDT
This is not part of the compilation process, I'm doing this after everything has been successfully compiled.

The code does hook into the weaver to recuperate the weaver world at the end of the compilation process. This is used to do some inspecting, e.g. to get at all the types known by the weaver (instances of org.aspectj.weaver.ResolvedType) and from there get their annotations by calling getAnnotations

HTH,
Comment 5 Andrew Clement CLA 2014-10-01 18:23:53 EDT
I see, thanks for the info. I can see how you could get into this state - now whether it is a supported state is another matter :)

Crafting a nice small testcase for this could be tricky, but I'll give it a go.
Comment 6 Andrew Clement CLA 2014-10-01 19:30:18 EDT
I tried but failed to create a test case.

There are numerous annotation type conversions that go on in EclipseSourceType.convertEclipseAnnotation but that code certainly doesn't handle all of them. This would be a case that it doesn't handle. But without a test case it is tricky to get the conversion correct. If you can't share with me a failing test case maybe you can provide the missing implementation as a pull request?  If you look at EclipseSourceType.convertEclipseAnnotation you can see the kinds of thing that it does and copy a nearby pattern.

What is confusing is that after compilation is finished there should be no EclipseSourceType objects left (IIRC). They should have all gone through the compilation and weaving process and be represented by Bcel types.