Handling of exported/library Annotations in new Java Software Model

Out of curiosity i tried migrating my java project to the new software model and noticed 2 problems:

1)

During exporting, annotations are stripped of their default values.

Minimal Example:
model library 1:

@Retention(RUNTIME)
@Target({FIELD,METHOD})
public @interface TestAnno {
    String name() default "none";

    String[] arr() default {};
}

model library 2:

public class Library {
    @TestAnno
    Object sth;
}

This fails, as library2 is compiled against only the api jar, which does not contain the annotations default values.
Workaround is to always define all values of annotations.

2)

I have had gradle crashing with annotations from a 3rd party library on public members of an exported class (Basically the same example as above, except the Annotation comes not out of a model library but a precompiled jar)
In my case this occurred when using the @Parameter(names={}) annotation of ‘com.beust:jcommander:1.48’.

Even when compiling the library as part of the build, with the above workaround it still chrashes.
The only further find i was able to discover, is that it only seemed to depend on the value of the String[] parameter, and that its name is sometimes read as ‘null’ by the gradle-internal class reader.

The stacktrace (parts left out for conciseness):

Caused by: java.lang.NullPointerException
        at com.google.common.collect.ComparisonChain$1.compare(ComparisonChain.java:76)
        at org.gradle.jvm.tasks.api.internal.Member.compare(Member.java:47)
        at org.gradle.jvm.tasks.api.internal.AnnotationValue.compareTo(AnnotationValue.java:34)
        at org.gradle.jvm.tasks.api.internal.AnnotationValue.compareTo(AnnotationValue.java:19)
        at org.gradle.jvm.tasks.api.internal.AnnotationMember.addValues(AnnotationMember.java:45)
        at org.gradle.jvm.tasks.api.internal.SortingAnnotationVisitor.visitEnd(SortingAnnotationVisitor.java:81)
        at org.objectweb.asm.ClassReader.a(Unknown Source)
        at org.objectweb.asm.ClassReader.a(Unknown Source)
        at org.objectweb.asm.ClassReader.a(Unknown Source)
        at org.objectweb.asm.ClassReader.b(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.gradle.jvm.tasks.api.internal.ApiClassExtractor.extractApiClassFrom(ApiClassExtractor.java:80)
        at org.gradle.jvm.tasks.api.ApiJar$1.writeClasses(ApiJar.java:126)
        at org.gradle.jvm.tasks.api.ApiJar$1.doExecute(ApiJar.java:108)
        at org.gradle.jvm.tasks.api.ApiJar$1.doExecute(ApiJar.java:104)
        at org.gradle.internal.ErroringAction.execute(ErroringAction.java:35)
        at org.gradle.internal.IoActions.withResource(IoActions.java:74)
        at org.gradle.jvm.tasks.api.ApiJar.createApiJar(ApiJar.java:102)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:227)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:220)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:209)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:585)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:568)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        ... 14 more

PS: if the (at)s are not showing up as such, then because the forum did not allow them because of their mention functionality

@CedricChampeau is this perhaps a consequence of how we are generating the API jar?

Yes, it definitely looks like a bug that needs to be fixed.

I’m currently blocked by that issue too. I can confirm it is a problem with the API jars, as compiling a file using the main jar works, but compiling it again the api jar fails.
If it is not fixed in 2.12, it may be worth a note in the known issues. (could save some time for people having the same problem).

In the meantime, since nothing changed up to the current gradle nightly i took a look at the source code and managed to find the reason for the NullpointerException and made a single line fix that seems to work for me.

It was rather obvious, since there are several null-checks, just 1 was missing and that was were the NullPointerException came from. The Values of Arrays inside annotations have no associated name (=null in your class). I just needed to add the same check that is done in several other places were “value” is given as name for instances that do not have an inherent name.

@CedricChampeau @mark_vieira If you like I am happy to make a Pull-Request for this single line fix.

Yes, absolutely! Thanks. :slight_smile: