Eu tenho o seguinte método em Java:
public void myMethod(
@ClosureParams(
value = SimpleType.class,
options = {
"java.util.Map"
}
) Closure<String> closure
) {
...
}
que tem @ClosureParams
de especificar os tipos de parâmetro de fechamento para o verificador de tipo estático e tipo de inferência no IDEA.
No script Groovy, eu chamar esse método como segue:
myMethod { Map<String, Object> doc ->
...
}
e ele funciona muito bem. Mas quando eu tento especificar tipos genéricos para java.util.Map
de fecho no meu método java:
public void myMethod(
@ClosureParams(
value = SimpleType.class,
options = {
"java.util.Map<java.lang.String,java.lang.Object>" // <-- added here
}
) Closure<String> closure
) {
...
}
verificador de tipo estático do Groovy falha com o erro:
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 ->
embora IDEA infere do tipo de doc
sem qualquer Map
ou Map<...>
usando @ClosureParams
dica.
Quando eu olhar para a fonte da groovy.transform.stc.SimpleType
classe, vejo que esta classe não dá a capacidade de especificar os tipos genéricos, pois utiliza simples 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;
}
A minha pergunta: como especificar fechamento tipo de parâmetro com os genéricos em Groovy? De preferência, com suporte em IDEA.
Você pode usar groovy.transform.stc.FromString
assinatura dica para obter os tipos genéricos de trabalho. Considere o seguinte exemplo:
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()
Ele compila e dá-lhe assinatura dica, também para o implícito it
variável.
O exemplo que se segue utiliza Groovy 2.5.7 .