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

Valentine updated GROOVY-11796:
-------------------------------
    Description: 
After upgrading to Groovy 5.0.x, the CompilationUnit.getClasses() method 
returns classes in an incorrect order when traits with closures are used.

 

When compiling a trait with a closure and a class that implements this trait, 
getClasses() returns classes in an order where the implementing class comes 
BEFORE the trait class.
This causes ClassNotFoundException when trying to define classes sequentially 
in a ClassLoader.

*Steps to reproduce*

this code with closure FAILS

 
{code:java}
trait MyTrait {
    MyTrait findByName(String name) {
        return values().find { it.name() == name }
    }
}
enum MyEnum implements MyTrait {
    A, B, C
}
{code}
 

*Actual order from getClasses()*

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_findByName_closure1
2 = MyEnum                    ← PROBLEM: MyEnum comes BEFORE MyTrait
3 = MyTrait

 

*This code without closure WORKS*

 
{code:java}
trait MyTrait {
    MyTrait findByName(String name) {
        for (def value : values()) {
            if (value.name() == name){ 
                 return value             
            }
        }
        return null
    }
}
 
enum MyEnum implements MyTrait {
  A, B, C
}
{code}
 

 

*Actual order from getClasses()*

0 = MyTrait
1 = MyTrait$Trait$Helper
2 = MyEnum                    ← CORRECT: MyEnum comes AFTER MyTrait

 

IMO this is regression because:

1. {*}Groovy 4.0.28{*}: This code worked correctly - classes were returned in 
proper dependency order.
2. {*}Groovy 5.0.0 and 5.0.1{*}: Even simple cases like

trait A {}
class B implements A{}

returned incorrect order.
3. {*}Groovy 5.0.2{*}: Simple cases were fixed, but the problem still persists 
when closures are used in traits.

Additionally, this code WORKS and getClasses() provides *correct* order.

 
{code:java}
trait MyTrait {
    static String test(int x) {
        def result
        switch {
           case 1: result = 'one'; break
           default: result = 'other'; break
        }
       return result
    }
}
enum MyEnum implements MyTrait
{  A, B }
{code}
 

{*}This code doesn't work{*}.

 
{code:java}
trait MyTrait {
    static String test(int x) {
        def result = switch (x) {
             case 1 -> 'one'
             default -> 'other'
        }
        return result
    }
}
enum MyEnum implements MyTrait { A, B }
{code}
 

getClasses() provides this order of classes.

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_test_closure1
2 = MyEnum   ← PROBLEM: MyEnum comes BEFORE MyTrait
3 = MyTrait

This code *doesn't work* either 

 
{code:java}
trait MyTrait {
    def process() { 
        values().stream()
             .filter(v -> v.name() == 'A')
             .findFirst()
     }
}
enum MyEnum implements MyTrait
{ A, B }
{code}
 

The same problem with the order. 

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_process_closure1
2 = MyEnum
3 = MyTrait

  was:
After upgrading to Groovy 5.0.x, the CompilationUnit.getClasses() method 
returns classes in an incorrect order when traits with closures are used.

 

When compiling a trait with a closure and a class that implements this trait, 
getClasses() returns classes in an order where the implementing class comes 
BEFORE the trait class.
This causes ClassNotFoundException when trying to define classes sequentially 
in a ClassLoader.

*Steps to reproduce*

this code with closure FAILS

 
{code:java}
trait MyTrait {
    MyTrait findByName(String name) {
        return values().find { it.name() == name }
    }
}
enum MyEnum implements MyTrait {
    A, B, C
}
{code}
 

*Actual order from getClasses()*

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_findByName_closure1
2 = MyEnum                    ← PROBLEM: MyEnum comes BEFORE MyTrait
3 = MyTrait

 

*This code without closure WORKS*

 
{code:java}
trait MyTrait {
    MyTrait findByName(String name) {
        for (def value : values()) {
            if (value.name() == name){ 
                 return value             
            }
        }
        return null
    }
}
 
enum MyEnum implements MyTrait {
  A, B, C
}
{code}
 

 

*Actual order from getClasses()*

0 = MyTrait
1 = MyTrait$Trait$Helper
2 = MyEnum                    ← CORRECT: MyEnum comes AFTER MyTrait

 

IMO this is regression because:

1. {*}Groovy 4.0.28{*}: This code worked correctly - classes were returned in 
proper dependency order.
2. {*}Groovy 5.0.0 and 5.0.1{*}: Even simple cases like

trait A {}
class B implements A{}

returned incorrect order.
3. {*}Groovy 5.0.2{*}: Simple cases were fixed, but the problem still persists 
when closures are used in traits.

Additionally, this code WORKS and getClasses() provides *correct* order.

 
{code:java}
trait MyTrait {
    static String test(int x) {
        def result
        switch {
           case 1: result = 'one'; break
           default: result = 'other'; break
        }
       return result
    }
}
enum MyEnum implements MyTrait
{  A, B }
{code}
 

{*}This code doesn't work{*}.

 
{code:java}
trait MyTrait {
    static String test(int x) {
        def result = switch {
             case 1 -> 'one'
             default -> 'other'
        }
        return result
    }
}
enum MyEnum implements MyTrait { A, B }
{code}
 

getClasses() provides this order of classes.

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_test_closure1
2 = MyEnum   ← PROBLEM: MyEnum comes BEFORE MyTrait
3 = MyTrait

This code *doesn't work* either 

 
{code:java}
trait MyTrait {
    def process() { 
        values().stream()
             .filter(v -> v.name() == 'A')
             .findFirst()
     }
}
enum MyEnum implements MyTrait
{ A, B }
{code}
 

The same problem with the order. 

0 = MyTrait$Trait$Helper
1 = MyTrait$Trait$Helper$_process_closure1
2 = MyEnum
3 = MyTrait


>  CompilationUnit.getClasses() returns classes in incorrect order when trait 
> with closure is used
> ------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-11796
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11796
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-jdk
>    Affects Versions: 5.0.0, 5.0.1, 5.0.2
>         Environment: Java version: OpenJDK 21
> OS: Linux
>            Reporter: Valentine
>            Priority: Major
>         Attachments: TraitOrderTest.java
>
>
> After upgrading to Groovy 5.0.x, the CompilationUnit.getClasses() method 
> returns classes in an incorrect order when traits with closures are used.
>  
> When compiling a trait with a closure and a class that implements this trait, 
> getClasses() returns classes in an order where the implementing class comes 
> BEFORE the trait class.
> This causes ClassNotFoundException when trying to define classes sequentially 
> in a ClassLoader.
> *Steps to reproduce*
> this code with closure FAILS
>  
> {code:java}
> trait MyTrait {
>     MyTrait findByName(String name) {
>         return values().find { it.name() == name }
>     }
> }
> enum MyEnum implements MyTrait {
>     A, B, C
> }
> {code}
>  
> *Actual order from getClasses()*
> 0 = MyTrait$Trait$Helper
> 1 = MyTrait$Trait$Helper$_findByName_closure1
> 2 = MyEnum                    ← PROBLEM: MyEnum comes BEFORE MyTrait
> 3 = MyTrait
>  
> *This code without closure WORKS*
>  
> {code:java}
> trait MyTrait {
>     MyTrait findByName(String name) {
>         for (def value : values()) {
>             if (value.name() == name){ 
>                  return value             
>             }
>         }
>         return null
>     }
> }
>  
> enum MyEnum implements MyTrait {
>   A, B, C
> }
> {code}
>  
>  
> *Actual order from getClasses()*
> 0 = MyTrait
> 1 = MyTrait$Trait$Helper
> 2 = MyEnum                    ← CORRECT: MyEnum comes AFTER MyTrait
>  
> IMO this is regression because:
> 1. {*}Groovy 4.0.28{*}: This code worked correctly - classes were returned in 
> proper dependency order.
> 2. {*}Groovy 5.0.0 and 5.0.1{*}: Even simple cases like
> trait A {}
> class B implements A{}
> returned incorrect order.
> 3. {*}Groovy 5.0.2{*}: Simple cases were fixed, but the problem still 
> persists when closures are used in traits.
> Additionally, this code WORKS and getClasses() provides *correct* order.
>  
> {code:java}
> trait MyTrait {
>     static String test(int x) {
>         def result
>         switch {
>            case 1: result = 'one'; break
>            default: result = 'other'; break
>         }
>        return result
>     }
> }
> enum MyEnum implements MyTrait
> {  A, B }
> {code}
>  
> {*}This code doesn't work{*}.
>  
> {code:java}
> trait MyTrait {
>     static String test(int x) {
>         def result = switch (x) {
>              case 1 -> 'one'
>              default -> 'other'
>         }
>         return result
>     }
> }
> enum MyEnum implements MyTrait { A, B }
> {code}
>  
> getClasses() provides this order of classes.
> 0 = MyTrait$Trait$Helper
> 1 = MyTrait$Trait$Helper$_test_closure1
> 2 = MyEnum   ← PROBLEM: MyEnum comes BEFORE MyTrait
> 3 = MyTrait
> This code *doesn't work* either 
>  
> {code:java}
> trait MyTrait {
>     def process() { 
>         values().stream()
>              .filter(v -> v.name() == 'A')
>              .findFirst()
>      }
> }
> enum MyEnum implements MyTrait
> { A, B }
> {code}
>  
> The same problem with the order. 
> 0 = MyTrait$Trait$Helper
> 1 = MyTrait$Trait$Helper$_process_closure1
> 2 = MyEnum
> 3 = MyTrait



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

Reply via email to