【问题标题】:Groovy: how to use inner Enum of class as parameter type outside of classGroovy:如何使用类的内部枚举作为类外的参数类型
【发布时间】:2019-03-29 10:51:38
【问题描述】:

Given 是一个类 EnumTest,它声明了一个内部枚举 MyEnum

在类中使用MyEnum 作为参数类型可以按预期工作。

使用MyEnum 作为EnumTest 之外的参数类型无法使用unable to resolve class test.EnumTest.MyEnum 进行编译。

我浏览过相关问题,其中最好的一个是this,但他们没有解决使用枚举作为类型的具体问题。

我是否在这里遗漏了一些非常明显的东西(因为我对 Groovy 很陌生)?或者这只是该语言关于枚举的另一个怪癖 “增强”

编辑:这只是一个演示问题的测试。实际问题发生在 Jenkins JobDSL 中,否则类路径和导入似乎还不错。

Groovy Version: 2.4.8
JVM: 1.8.0_201 
Vendor: Oracle Corporation
OS: Linux

$ tree test
test
├── EnumTest.groovy
├── File2.groovy
└── File3.groovy

EnumTest.groovy:

package test

public class EnumTest {
  public static enum MyEnum {
    FOO, BAR 
  }

  def doStuff(MyEnum v) {
    println v
  }
}

文件2.groovy:

package test

import test.EnumTest 

// prints BAR 
new EnumTest().doStuff(EnumTest.MyEnum.BAR)

// prints FOO 
println EnumTest.MyEnum.FOO

文件3.groovy:

package test

import test.EnumTest

// fails: unable to resolve class test.EnumTest.MyEnum
def thisShouldWorkIMHO(EnumTest.MyEnum v) {
   println v
}

当我使用groovy -cp % 运行测试文件时,输出如下:

# groovy -cp . File2.groovy
BAR
FOO

# groovy -cp . File3.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/home/lwille/-/test/GroovyTest2.groovy: 6: unable to resolve class EnumTest.MyEnum 
 @ line 6, column 24.
   def thisShouldWorkIMHO(EnumTest.MyEnum v) {
                          ^

1 error

【问题讨论】:

    标签: groovy enums


    【解决方案1】:

    有几点值得一提。您不需要从同一个包中导入类。其次,当您使用包 test 时,您需要从根文件夹执行 Groovy,例如groovy test/File3.groovy 正确设置类路径。 (这种情况下不需要使用-cp .)。

    它应该是这样的。

    $ tree test 
    test
    ├── EnumTest.groovy
    ├── File2.groovy
    └── File3.groovy
    
    0 directories, 3 files
    

    test/EnumTest.groovy

    package test
    
    public class EnumTest {
        public static enum MyEnum {
            FOO, BAR
        }
    
        def doStuff(MyEnum v) {
            println v
        }
    }
    

    test/File2.groovy

    package test
    
    // prints BAR
    new EnumTest().doStuff(EnumTest.MyEnum.BAR)
    
    // prints FOO
    println EnumTest.MyEnum.FOO
    

    test/File3.groovy

    package test
    
    // fails: unable to resolve class test.EnumTest.MyEnum
    def thisShouldWorkIMHO(EnumTest.MyEnum v) {
        println v
    }
    
    thisShouldWorkIMHO(EnumTest.MyEnum.BAR)
    

    控制台输出:

    $ groovy test/File2.groovy 
    BAR
    FOO
    
    $ groovy test/File3.groovy
    BAR
    

    但是,如果您想从 test 文件夹中执行脚本,则需要指定类路径以指向父文件夹,例如:

    $ groovy -cp ../. File3.groovy
    BAR
    
    $ groovy -cp . File3.groovy   
    org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
    /home/wololock/workspace/groovy-sandbox/src/test/File3.groovy: 4: unable to resolve class EnumTest.MyEnum 
     @ line 4, column 24.
       def thisShouldWorkIMHO(EnumTest.MyEnum v) {
                              ^
    
    1 error
    

    更新:Groovy 2.4 和 2.5 版本的区别

    有一点值得一提——上述解决方案适用于 Groovy 2.5.x 及更高版本。重要的是要了解方法参数类型检查等事情发生在编译器的Phase.SEMANTIC_ANALYSIS 阶段。在 Groovy 2.4 版本中,语义分析类解析发生在不加载类的情况下。在使用内部类的情况下,加载其外部类以便解决问题至关重要。 Groovy 2.5 修复了该问题(有意或无意),语义分析解决了内部类,而没有本问题中提到的问题。

    如需更详细的分析,请查看以下 Stack Overflow 问题GroovyScriptEngine throws MultipleCompilationErrorsException while loading class that uses other class' static inner class,我在其中调查了在 Groovy 2.4 脚本中发现的类似问题。我在那里一步一步地解释了如何挖掘这个问题的根源。

    【讨论】:

    • 感谢您的回答!如果我的环境是原因,为什么文件 2 工作?这只是一个证明问题的测试。实际问题发生在 Jenkins JobDSL 中,否则类路径和导入似乎没问题。
    • 现在我测试了建议的更改,无论我设置类路径还是跳过导入类,它都不会改变任何东西。我的 Groovy 版本是 2.4.8,你的是什么?
    • 我使用了 Groovy 2.5.6,我可以确认这个问题存在于任何 Groovy 2.4.x 版本中(我检查了 2.4.8 以及最新的 2.4.16)。您的问题听起来与我大约一年前调查的问题非常相似(stackoverflow.com/q/52294765/2194470)。长话短说 - 方法参数类型在编译器的 Phase.SEMANTIC_ANALYSIS 阶段解析。这里的问题是(至少在 Groovy 2.4 中)这个编译阶段不加载类,任何内部类都需要加载它的外部类才能解决。 Groovy 2.5 解决了它(有意或无意)。
    • 请把它写成答案,我会接受的。感谢您的支持!
    • 完成。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 2013-10-12
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多