ClosureParams:如何在groovy

时间:2019-07-03 08:24:54

标签: java groovy closures

我在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使用doc提示来推断Map的类型而没有任何Map<...>@ClosureParams

当我查看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中得到支持。

1 个答案:

答案 0 :(得分:4)

您可以使用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变量。

enter image description here

以下示例使用Groovy 2.5.7