Получите аннотированные функции в сценарии Kotlin (и других сценариях языка JVM) с API сценариев Java - PullRequest
0 голосов
/ 20 марта 2019

Можно ли получить все функции верхнего уровня в файле сценария Kotlin (* .kts), которые украшены определенной аннотацией, с помощью API сценариев Java JSR 223 без необходимости изменять и оценивать сценарий (т.е. только путем компиляциисценарий с Java Scripting API)?

Требуется иметь возможность получать метаданные для функций в сценариях.Имена функций заранее неизвестны, и функции будут вызываться только позже.Он должен работать универсальным образом для сценария, написанного в любой реализации языка JVM с поддержкой JSR 223 (Kotlin, Groovy, JavaScript, JRuby и т. Д.).

Ниже показан тестовый проект.

Структура тестового проекта:

+---script-functions
|   |   pom.xml
|   |
|   +---src
|   |   +---main
|   |   |   +---java
|   |   |   |   \---scriptfun
|   |   |   |           Main.java
|   |   |   |           MyAnnotation.java
|   |   |   |
|   |   |   \---resources
|   |   |       \---META-INF
|   |   |           \---services
|   |   |                   javax.script.ScriptEngineFactory

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>script-tests</groupId>
    <artifactId>script-functions</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <kotlin.version>1.3.21</kotlin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-script-util</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-compiler-embeddable</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
    </dependencies>
</project>

MyAnnotation.java:

package scriptfun;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}

Main.java:

package scriptfun;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.script.*;

public class Main {

    private static final String SCRIPT
            = "@scriptfun.MyAnnotation()\n"
            + "fun unknownFun(): Int {\n"
            + "   return 0\n"
            + "}";

    public static void main(String[] args) throws Exception {
        boolean evalScript = false;
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByExtension("kts");
        if (evalScript) {
            // This works, but the script must be wrapped and evaluated and the code is specific to Kotlin
            String script = "val obj = object {" + SCRIPT + "}\n"
                    + "obj";
            Object obj = engine.eval(script);
            Method method = obj.getClass().getDeclaredMethods()[0];
            Annotation annotation = method.getAnnotations()[0];
            System.out.println("obj = " + obj); // obj = Line_1$obj$1@7fa255ee
            System.out.println("method = " + method); // method = public final int Line_1$obj$1.unknownFun()
            System.out.println("annotation = " + annotation); // annotation = @scriptfun.MyAnnotation()
        } else {
            if (engine instanceof Compilable) {
                Compilable compilable = (Compilable) engine;
                CompiledScript compiledScript = compilable.compile(SCRIPT);
                // HELP How do I get the Method and Annotation here?
            }
        }
    }
}
...