【问题标题】:ClosureParams: how to specify generic types for closure parameter in groovyClosureParams:如何在 groovy 中为闭包参数指定泛型类型
【发布时间】:2019-11-13 21:26:46
【问题描述】:

我在Java中有以下方法:

public void myMethod(
        @ClosureParams(
                value = SimpleType.class,
                options = {
                        "java.util.Map"
                }
        ) Closure<String> closure
) {
    ...
}

其中有 @ClosureParams 来指定闭包的参数类型,用于 IDEA 中的静态类型检查和类型推断。

在 Groovy 脚本中,我这样调用这个方法:

myMethod { Map<String, Object> doc ->
    ...
}

而且效果很好。但是,当我尝试在我的 java 方法中为 java.util.Map 的闭包指定 通用类型 时:

public void myMethod(
        @ClosureParams(
                value = SimpleType.class,
                options = {
                        "java.util.Map<java.lang.String,java.lang.Object>" // <-- added here
                }
        ) Closure<String> closure
) {
    ...
}

groovy 的静态类型检查器因错误而失败:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
C:\myproject\script.groovy: 1: Expected parameter of type java.util.Map<java.lang.String,java.lang.Object> but got java.util.Map <String, Object>
 @ line 1, column 8.
myMethod { Map<String, Object> doc ->

虽然 IDEA 使用 @ClosureParams 提示推断 doc 的类型而没有任何 Map 或 Map&lt;...&gt;。

当我查看groovy.transform.stc.SimpleType 类的源代码时,我发现这个类没有指定泛型类型的能力,因为它使用普通的Class.forName:

public class SimpleType extends SingleSignatureClosureHint {
    @Override
    public ClassNode[] getParameterTypes(final MethodNode node, final String[] options, final SourceUnit sourceUnit, final CompilationUnit unit, final ASTNode usage) {
        ClassNode[] result = new ClassNode[options.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = findClassNode(sourceUnit, unit, options[i]);
        }
        return result;
    }
 }

    // findClassNode method:
    protected ClassNode findClassNode(final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final String className) {
        if (className.endsWith("[]")) {
            return findClassNode(sourceUnit, compilationUnit, className.substring(0, className.length() - 2)).makeArray();
        }
        ClassNode cn = compilationUnit.getClassNode(className);
        if (cn == null) {
            try {
                cn = ClassHelper.make(Class.forName(className, false, sourceUnit.getClassLoader()));
            } catch (ClassNotFoundException e) {
                cn = ClassHelper.make(className);
            }
        }
        return cn;
    }

我的问题:如何在 groovy 中使用泛型指定闭包参数类型?最好有 IDEA 的支持。

【问题讨论】:

    标签: java groovy closures


    【解决方案1】:

    您可以使用groovy.transform.stc.FromString 签名提示来使泛型类型正常工作。考虑以下示例:

    JavaClass.java

    import groovy.lang.Closure;
    import groovy.transform.stc.ClosureParams;
    import groovy.transform.stc.FromString;
    
    import java.util.HashMap;
    
    public class JavaClass {
    
        public static void processRendered(@ClosureParams(
                value = FromString.class,
                options = {"java.util.Map<java.lang.String,java.lang.Object>"}) Closure closure) {
    
            closure.call(new HashMap<String, Object>());
        }
    }
    

    script.groovy

    import groovy.transform.CompileStatic
    import static JavaClass.processRendered
    
    @CompileStatic
    def test() {
      processRendered { Map<String, Object> map ->
        map.put("test", 1)
      }
    
      processRendered {
        it.put("test", 2)
      }
    }
    
    test()
    

    它编译并为您提供签名提示,也适用于隐式 it 变量。

    以下示例使用 Groovy 2.5.7。

    【讨论】:

    • 您使用哪个版本的 IDEA?
    • @cybersoft IntelliJ IDEA 2018.3.6(终极版)
    • 嗯..我在 2018.3.3 UE 上运行,它抱怨“无法推断类型”:(我的闭包有两个参数,但我认为没关系。会尝试更新 IDEA。 ..
    • @cybersoft 我检查了java.util.Map&lt;java.lang.String,java.lang.Object&gt;, java.lang.String 等两个参数的签名提示,没有问题。此外,我已将我的 IntelliJ IDEA 更新为 2019.1.3 - 也适用于此版本。关于更新 IDEA 的一个提示 - “更新并重新启动”破坏了我的 2018.3.6(我无法打开任何源文件),我不得不手动安装 2019.1.3。
    • 是的,你是对的,现在它可以工作了。 Javadoc 提到了这一点:where each string corresponds to a single signature 但我认为它与SimpleType 一样工作。一般来说,groovy doc 对这些事情没有那么详细。非常感谢!对不起,我的英语不好。
    猜你喜欢
    • 2011-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2011-08-06
    相关资源
    最近更新 更多