Код: Выделить всё
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 Код: Выделить всё
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