Valentine created GROOVY-11796:
----------------------------------

             Summary:  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.2, 5.0.1, 5.0.0
         Environment: Java version: OpenJDK 21
OS: Linux
            Reporter: Valentine
         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

 
{color:#172b4d}trait MyTrait {{color}
{color:#172b4d}    MyTrait findByName(String name) {{color}
{color:#172b4d}        return values().find \{ it.name() == name }{color}
{color:#172b4d}    }{color}
{color:#172b4d}}{color}

{color:#172b4d}enum MyEnum implements MyTrait {{color}
{color:#172b4d}    A, B, C{color}
{color:#172b4d}}{color}
 

*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*

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
}

 

*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.



trait MyTrait {
    static String test(int x) {
        def result
        switch (x) {
            case 1: result = 'one'; break
            default: result = 'other'; break
        }
        return result
    }
}

enum MyEnum implements MyTrait {
    A, B
}

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

trait MyTrait {
    static String test(int x) {
        def result = switch (x) {
            case 1 -> 'one'
            default -> 'other'
        }
        return result
    }
}

enum MyEnum implements MyTrait {
    A, B
}

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 

trait MyTrait {
    def process() {
        values().stream()
            .filter(v -> v.name() == 'A')
            .findFirst()
    }
}

enum MyEnum implements MyTrait {
    A, B
}

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