Статически компилировать Groovy Delegatingscript с делегированным объектом, содержащим метод с закрытиемJAVA

Программисты JAVA общаются здесь
Anonymous
Статически компилировать Groovy Delegatingscript с делегированным объектом, содержащим метод с закрытием

Сообщение Anonymous »

У меня есть следующие классы < /p>

Код: Выделить всё

final class GroovyValidator {

@Override
public List validate(String script) {
final CompilerConfiguration config = new CompilerConfiguration();
config.setScriptBaseClass("groovy.util.DelegatingScript");
config.addCompilationCustomizers(new ASTTransformationCustomizer(
Map.of("extensions", List.of(ConnectorTypeCheckExtension.class.getName())),
CompileStatic.class));

try {
final GroovyShell shell = new GroovyShell(this.getClass().getClassLoader(), config);
// compile the script
final DelegatingScript parsedScript = (DelegatingScript) shell.parse(script);
parsedScript.setDelegate(new ObjectClass());
parsedScript.run();
} catch (MultipleCompilationErrorsException e) {
return e.getErrorCollector().getErrors().stream()
.map(m -> {
final StringWriter stringWriter = new StringWriter();
m.write(new PrintWriter(stringWriter));
return stringWriter.toString();
})
.toList();

}
return Collections.emptyList();
}

}

< /code>
public class ObjectClass {

public ObjectClass objectClass(String name,
@DelegatesTo(value = String.class, strategy = Closure.DELEGATE_FIRST) Closure closure) {
closure.setDelegate(name);
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure.call();
return this;
}
}

< /code>
public class ConnectorTypeCheckExtension extends AbstractTypeCheckingExtension {

public ConnectorTypeCheckExtension(StaticTypeCheckingVisitor typeCheckingVisitor) {
super(typeCheckingVisitor);
}

@Override
public List handleMissingMethod(ClassNode receiver, String name, ArgumentListExpression argumentList,
ClassNode[] argumentTypes, MethodCall call) {
System.out.printf("Handling missing %s\n", name);
if ("objectClass".equals(name)) {
final ClassNode objectClassNode = classNodeFor(ObjectClass.class);
/*
Without bellow call to `delegatesTo` I am getting
[Script1.groovy: 2: [Static type checking] - Cannot find matching method Script1#concat(java.lang.String). Please check if the declared type is correct and if the method exists.
*/
delegatesTo(classNodeFor(String.class), Closure.DELEGATE_FIRST);
return List.of(makeDynamic(call, objectClassNode));
}

return Collections.emptyList();
}
}
< /code>
и следующий тест < /p>
    @Test
void scriptContainsKnownMethodClosure_validateIsCalled_validationShouldPass() {
final String script = """
objectClass("User") {
println concat("X")
}
""";

final GroovyValidator validator = new GroovyValidator();
final List errors = validator.validate(script);

System.out.println(errors);
assertTrue(errors.isEmpty());

}
< /code>
Я ожидаю, что тест пройдет. В частности, я ожидаю, что будет вызван метод ObjectClass 
из класса ObjectClass , а затем будет напечатана объединение «пользователя» с буквой «x». Но вместо этого он не работает во время выполнения, с этим сообщением об ошибке: < /p>

Код: Выделить всё

java.lang.ClassCastException: class Script1 cannot be cast to class groovy.lang.Closure (Script1 is in unnamed module of loader groovy.lang.GroovyClassLoader$InnerLoader @6cc0bcf6; groovy.lang.Closure is in unnamed module of loader 'app')
< /code>
Я действительно не понимаю эту ошибку. Почему это происходит? Проблема где -то в расширении типа? Или невозможно составить сценарий, подобный вышеуказанному, статически, учитывая, что метод, вызванный сценарием, является методом делегата? Как он узнает, в чем это аргумент? Я имею в виду метод ObjectClass 
имеет два аргументных имени , который является строкой, а затем закрытие . Я предполагаю, что в этом случае он может выбрать правильный, но что, если бы было два или более параметров закрытия? На самом деле я, скорее всего, буду использовать этот подход. Тем не менее, я действительно хотел бы понять, что происходит в описанном случае.


Подробнее здесь: https://stackoverflow.com/questions/796 ... ining-meth

Вернуться в «JAVA»