Может ли ToolProvider.getSystemJavaCompiler () получать доступ к среде выполнения, сгенерированной в исходных файлах памяти при использовании модулей JPMS? - PullRequest
1 голос
/ 01 февраля 2020

Я разработал приложение, которое генерирует источник Java во время выполнения из внешнего источника. Сгенерированный исходный код реализует интерфейс, скажем, org.foo, а также вызывает другие классы, расположенные в org.foo. Приложение скомпилировало сгенерированный источник Java в указанный пакет c, скажем org.foo.generated. Компилятор, предоставленный ToolProvider.getSystemJavaCompiler(), нашел исходные файлы, используя ForwardingJavaFileManager, скомпилировал исходные файлы, и приложение смогло их запустить.

Теперь я разделил свое приложение на модули JPMS, и компилятор жалуется, что не может найти пакет org.foo, в котором живет интерфейс, реализованный сгенерированным исходным кодом. Я вызываю компилятор из того же модуля (org.foo), где живет сгенерированный код. Сообщение об ошибке выглядит следующим образом:

пакет org.foo не существует

Я изменил свой ForwardingFileManager, добавив некоторые методы для поиска модулей, как описано здесь . Похоже, компилятор, находящийся в модуле java.compiler, не может получить доступ к модулю org.foo. Итак, я добавил

- add-reads java .compiler = org.foo

в командной строке, но это ничего не изменило. Есть какие-нибудь подсказки? Есть ли у кого-нибудь положительный опыт объединения исходных файлов во время выполнения и JPMS с Janino вместо компилятора ToolProvider?

Ниже приведен минимальный воспроизводимый пример, запрошенный в комментариях. Исходные файлы также могут быть получены из github:

https://github.com/evg/demo-jpms-compiler.git

Я получаю следующий вывод без Информация о модуле. java:

All files compiled without errors: true
0 diagnostics reported by compiler task

I получить следующий вывод с информация о модуле. java:

All files compiled without errors: false
3 diagnostics reported by compiler task
DIAGNOSTIC /org/foo/generated/MyGreeter.java:5: error: cannot find symbol
public class MyGreeter implements IGreeter {
                                  ^
  symbol: class IGreeter
DIAGNOSTIC /org/foo/generated/MyGreeter.java:3: error: package org.foo does not exist
import org.foo.*;
^
DIAGNOSTIC /org/foo/generated/MyGreeter.java:6: error: method does not override or implement a method from a supertype
  @Override
  ^

Командные строки, которые использует Eclipse. Без module-info. java:

C:\Program Files\Java\jdk-11.0.2\bin\javaw.exe -Dfile.encoding=Cp1252 -classpath "H:\git\demo-jpms-compiler\demo-jpms-compiler\target\classes" org.foo.Main

С module-info. java:

C:\Program Files\Java\jdk-11.0.2\bin\javaw.exe -Dfile.encoding=Cp1252 -p "H:\git\demo-jpms-compiler\demo-jpms-compiler\target\classes" -m org.foo/org.foo.Main

Файлы используется:

module-info. java

module org.foo {
  requires java.compiler;
}

Main. java

package org.foo;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

public class Main {

    public static void main(String[] args) {
        new Main().run();
    }

    private void run() {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        Iterable<? extends JavaFileObject> compilationUnits = List.of(new JavaSourceFromString("org.foo.generated.MyGreeter", getJavaSource()));
        JavaCompiler.CompilationTask task = compiler.getTask(null, null, diagnosticCollector , compilerOptions, null, compilationUnits);
        boolean allFilesCompiledWithoutErrors = task.call();
        log("All files compiled without errors: " + allFilesCompiledWithoutErrors);
        log(diagnosticCollector.getDiagnostics().size() + " diagnostics reported by compiler task");
        diagnosticCollector.getDiagnostics().stream().forEach(diagnostic->{
            log("DIAGNOSTIC " + diagnostic);
        });
    }

    private void log(String text) {
        System.out.println(text);
    }

    private String getJavaSource() {
        String[] lines = new String[] {
                "package org.foo.generated;",
                "",
                "import org.foo.*;",
                "",
                "public class MyGreeter implements IGreeter {",
                "  @Override",
                "  public String getGreeting() {",
                "    return \"Hello, generated world\";",
                "  }",
                "",
                "}"
        };
        return Stream.of(lines).collect(Collectors.joining(System.lineSeparator()));
    }

    private DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
    private List<String> compilerOptions = Arrays.asList("-Xlint:deprecation");
}

IGreeter. java

package org.foo;

public interface IGreeter {
  public String getGreeting();
}

JavaSourceFromString. java

package org.foo;

import java.net.URI;

import javax.tools.SimpleJavaFileObject;

/**
 * A file object used to represent source coming from a string.
 */
public class JavaSourceFromString extends SimpleJavaFileObject {
    /**
     * The source code of this "file".
     */
    final String code;

    /**
     * Constructs a new JavaSourceFromString.
     * 
     * @param name
     *            the name of the compilation unit represented by this file object
     * @param code
     *            the source code for the compilation unit represented by this file
     *            object
     */
    public JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...