You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Olof Asbrink (Jira)" <ji...@apache.org> on 2022/11/28 20:00:00 UTC

[jira] [Commented] (GROOVY-10857) Compiler enter infinite loop when compiling circular meta annotations

    [ https://issues.apache.org/jira/browse/GROOVY-10857?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17640236#comment-17640236 ] 

Olof Asbrink commented on GROOVY-10857:
---------------------------------------

[~emilles] Thanks for the quick turn around.

> Compiler enter infinite loop when compiling circular meta annotations
> ---------------------------------------------------------------------
>
>                 Key: GROOVY-10857
>                 URL: https://issues.apache.org/jira/browse/GROOVY-10857
>             Project: Groovy
>          Issue Type: Bug
>          Components: Compiler
>    Affects Versions: 4.0.6
>         Environment: Groovy 4.0.6, openjdk 17.0.4.1, Guava 31.1-jre
>            Reporter: Olof Asbrink
>            Assignee: Eric Milles
>            Priority: Major
>              Labels: StackOverflowError
>             Fix For: 4.0.7
>
>
> When I compile groovy that uses Java classes that has circular meta annotations in their class hierarcy. The compile crash with:
> {code:java}
> >>> a serious error occurred: null
> >>> stacktrace:
> java.lang.StackOverflowError
>         at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
>         at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
>         at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
>         at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
>         at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
>         at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
>         at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
>         at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:632)
>         at org.codehaus.groovy.ast.ClassNode.<init>(ClassNode.java:349)
>         at org.codehaus.groovy.ast.ClassNode.<init>(ClassNode.java:327)
>         at org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching(ClassHelper.java:281)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:123)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
>         at org.apache.groovy.contracts.util.AnnotationUtils.hasMetaAnnotations(AnnotationUtils.java:125)
> ... {code}
> this can be produced with this small example (2 java files and 1 groovy file):
> MyMetaAnnotation.java:
> {code:java}
> import static java.lang.annotation.ElementType.TYPE;
> import static java.lang.annotation.ElementType.METHOD;
> import static java.lang.annotation.RetentionPolicy.RUNTIME;
> import java.lang.annotation.Retention;
> import java.lang.annotation.Target;
> @Retention(RUNTIME)
> @Target({TYPE, METHOD})
> @MyMetaAnnotation
> public @interface MyMetaAnnotation {} {code}
> MyAnnotation.java:
> {code:java}
> import static java.lang.annotation.ElementType.FIELD;
> import static java.lang.annotation.ElementType.METHOD;
> import static java.lang.annotation.ElementType.PARAMETER;
> import static java.lang.annotation.RetentionPolicy.RUNTIME;
> import java.lang.annotation.Retention;
> import java.lang.annotation.Target;
> @MyMetaAnnotation
> @Retention(RUNTIME)
> @Target({FIELD, METHOD, PARAMETER})
> public @interface MyAnnotation {} {code}
> and UseMyAnnotation.groovy
> {code:java}
> import MyAnnotation
> public interface A<T> {
>       @MyAnnotation
>       T a()
> }
>       
> def b = new A() {
>     def a() { return 0 }
> } {code}
> A real world example is using some Guava classes which several has circularities in their meta annotations (e.g. com.google.common.base.Supplier) . This example will yield the same stackoverflow:
> {code:java}
> import com.google.common.base.Supplier
> def zeroSupplier = new Supplier() {
>     def get() { return 0 }
> }
> {code}
> Note that circularity in meta annotations is permitted according to the java spec:
> {quote}An annotation of interface A may appear as a meta-annotation on the declaration of the interface A itself. More generally, circularities in the transitive closure of the "annotates" relation are permitted.
> {quote}
> (from [https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.1)]
>  
> Also note. These compile succesfully using Groovy 3.0.11
>  
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)