[ 
https://issues.apache.org/jira/browse/GROOVY-12089?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Mattias Reichel updated GROOVY-12089:
-------------------------------------
    Description: 
With Groovy 5, a Grails domain class annotated with both {{@Entity}} and 
{{@Sortable}} can fail during canonicalization with:
{code:java}
BUG! exception in phase 'canonicalization' in source unit '...' unexpected 
NullPointerException
Caused by: java.lang.NullPointerException: Cannot read the array length because 
"<local3>" is null
    at 
org.codehaus.groovy.classgen.VariableScopeVisitor.visitConstructorOrMethod(...)
    at 
org.codehaus.groovy.transform.SortableASTTransformation.createSortable(...){code}
A minimal reproducer is:
{code:java}
import grails.persistence.Entity
import groovy.transform.Sortable
@Entity
@Sortable(includes = ['a'])
class Repro {
    String a
}

{code}
{{@Sortable}} by itself compiles, and {{@Entity}} by itself compiles. The 
failure only appears when they are combined.

According to GPT, the Groovy-side branch that introduces the null exceptions 
array is in {{{}org.codehaus.groovy.ast.ClassNode#getGetterMethod(String){}}}, 
specifically the default-argument getter synthesis branch:
{code:java}
} else if (method.hasDefaultValue() && 
Stream.of(method.getParameters()).allMatch(Parameter::hasInitialExpression)) {
    // GROOVY-11380: getter generated later by default arguments
    if (isNullOrSynthetic.test(getterMethod)) {
        getterMethod = new MethodNode(method.getName(), method.getModifiers() & 
~ACC_ABSTRACT, method.getReturnType(), Parameter.EMPTY_ARRAY, 
method.getExceptions(), null);
        getterMethod.setSynthetic(true);
        getterMethod.setDeclaringClass(this);
        getterMethod.addAnnotations(method.getAnnotations());
        AnnotatedNodeUtils.markAsGenerated(this, getterMethod);
        getterMethod.setGenericsTypes(method.getGenericsTypes());
    }
}
{code}
If the source method carries a null exceptions array, that null is preserved on 
the synthesized getter and later blows up in 
{{{}VariableScopeVisitor.visitConstructorOrMethod(...){}}}.

 

 

  was:
With Groovy 5, a Grails domain class annotated with both `@Entity` and 
`@Sortable` can fail during canonicalization with:
{code:java}
BUG! exception in phase 'canonicalization' in source unit '...' unexpected 
NullPointerException
Caused by: java.lang.NullPointerException: Cannot read the array length because 
"<local3>" is null
    at 
org.codehaus.groovy.classgen.VariableScopeVisitor.visitConstructorOrMethod(...)
    at 
org.codehaus.groovy.transform.SortableASTTransformation.createSortable(...){code}
A minimal reproducer is:
{code:java}
import grails.persistence.Entity
import groovy.transform.Sortable
@Entity
@Sortable(includes = ['a'])
class Repro {
    String a
}

{code}
`@Sortable` by itself compiles, and `@Entity` by itself compiles. The failure 
only appears when they are combined.

According to GPT, the Groovy-side branch that introduces the null exceptions 
array is in `org.codehaus.groovy.ast.ClassNode#getGetterMethod(String)`, 
specifically the default-argument getter synthesis branch:
{code:java}
} else if (method.hasDefaultValue() && 
Stream.of(method.getParameters()).allMatch(Parameter::hasInitialExpression)) {
    // GROOVY-11380: getter generated later by default arguments
    if (isNullOrSynthetic.test(getterMethod)) {
        getterMethod = new MethodNode(method.getName(), method.getModifiers() & 
~ACC_ABSTRACT, method.getReturnType(), Parameter.EMPTY_ARRAY, 
method.getExceptions(), null);
        getterMethod.setSynthetic(true);
        getterMethod.setDeclaringClass(this);
        getterMethod.addAnnotations(method.getAnnotations());
        AnnotatedNodeUtils.markAsGenerated(this, getterMethod);
        getterMethod.setGenericsTypes(method.getGenericsTypes());
    }
}
{code}
If the source method carries a null exceptions array, that null is preserved on 
the synthesized getter and later blows up in 
`VariableScopeVisitor.visitConstructorOrMethod(...)`.

 

 


> Groovy 5 ClassNode.getGetterMethod() can clone a getter with a null 
> exceptions array when @Entity and @Sortable are combined
> ----------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12089
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12089
>             Project: Groovy
>          Issue Type: Bug
>          Components: AST Transforms
>    Affects Versions: 5.0.6
>            Reporter: Mattias Reichel
>            Priority: Major
>
> With Groovy 5, a Grails domain class annotated with both {{@Entity}} and 
> {{@Sortable}} can fail during canonicalization with:
> {code:java}
> BUG! exception in phase 'canonicalization' in source unit '...' unexpected 
> NullPointerException
> Caused by: java.lang.NullPointerException: Cannot read the array length 
> because "<local3>" is null
>     at 
> org.codehaus.groovy.classgen.VariableScopeVisitor.visitConstructorOrMethod(...)
>     at 
> org.codehaus.groovy.transform.SortableASTTransformation.createSortable(...){code}
> A minimal reproducer is:
> {code:java}
> import grails.persistence.Entity
> import groovy.transform.Sortable
> @Entity
> @Sortable(includes = ['a'])
> class Repro {
>     String a
> }
> {code}
> {{@Sortable}} by itself compiles, and {{@Entity}} by itself compiles. The 
> failure only appears when they are combined.
> According to GPT, the Groovy-side branch that introduces the null exceptions 
> array is in 
> {{{}org.codehaus.groovy.ast.ClassNode#getGetterMethod(String){}}}, 
> specifically the default-argument getter synthesis branch:
> {code:java}
> } else if (method.hasDefaultValue() && 
> Stream.of(method.getParameters()).allMatch(Parameter::hasInitialExpression)) {
>     // GROOVY-11380: getter generated later by default arguments
>     if (isNullOrSynthetic.test(getterMethod)) {
>         getterMethod = new MethodNode(method.getName(), method.getModifiers() 
> & ~ACC_ABSTRACT, method.getReturnType(), Parameter.EMPTY_ARRAY, 
> method.getExceptions(), null);
>         getterMethod.setSynthetic(true);
>         getterMethod.setDeclaringClass(this);
>         getterMethod.addAnnotations(method.getAnnotations());
>         AnnotatedNodeUtils.markAsGenerated(this, getterMethod);
>         getterMethod.setGenericsTypes(method.getGenericsTypes());
>     }
> }
> {code}
> If the source method carries a null exceptions array, that null is preserved 
> on the synthesized getter and later blows up in 
> {{{}VariableScopeVisitor.visitConstructorOrMethod(...){}}}.
>  
>  



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

Reply via email to