Компиляция класса во время выполнения с classpath

В настоящее время я пытаюсь скомпилировать класс во время выполнения, но по какой-то причине он работает только в одной системе. Обе системы используют один и тот же код и имеют одну и ту же версию Java, но в одной системе мой файл .java компилируется в .class, а в другой системе я получаю исключения, потому что некоторые классы, которые есть или должны быть в classpath не может быть найден.

Код, который я использую для его компиляции, таков:

private static File compile(File file) {
    try {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        List<String> optionList = new ArrayList<>();
        File jar = getJar(RuntimeCompiler.class);
        File pluginDirectory = new File(jar.getAbsolutePath().substring(0, jar.getAbsolutePath().length() - jar.getName().length()));
        String classes = buildClassPath(getJar(Bukkit.class).getAbsolutePath(), pluginDirectory.getAbsolutePath() + "/*");
        optionList.addAll(Arrays.asList("-classpath",classes));
        boolean success;
        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null )) {
            Iterable<? extends JavaFileObject> units;
            units = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(file));
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, optionList, null, units);
            success = task.call();
        }
        if(success) {
            return new File(file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - 5) + ".class");
        }
        else {
            return null;
        }
    } catch (IOException ex) {
        Logger.getLogger(RuntimeCompiler.class.getName()).log(Level.SEVERE, null, ex);
        return null;
    }
}
private static String buildClassPath(String... paths) {
    StringBuilder sb = new StringBuilder();
    for (String path : paths) {
        if (path.endsWith("*")) {
            path = path.substring(0, path.length() - 1);
            File pathFile = new File(path);
            for (File file : pathFile.listFiles()) {
                if (file.isFile() && file.getName().endsWith(".jar")) {
                    sb.append(path);
                    sb.append(file.getName());
                    sb.append(System.getProperty("path.separator"));
                }
            }
        } else {
            sb.append(path);
            sb.append(System.getProperty("path.separator"));
        }
    }
    String s = sb.toString();
    s = s.substring(0,s.length() - 1);
    return s;
}

classpath (optionList.toString()) с Core-1.0-SNAPSHOT.jar, содержащим необходимые файлы.

[-classpath, /usr/local/gpx/users/user/127.0.0.1:25702/spigot.jar:25702/plugins/Core-1.0-SNAPSHOT.jar]

Трассировки стека

/usr/local/gpx/users/user/127.0.0.1:25702/plugins/debug/DebugClass.java:1: error: package     net.nowcraft.core does not exist
[14:04:10] [Server thread/WARN]: import net.nowcraft.core.core;
[14:04:10] [Server thread/WARN]:                         ^
[14:04:10] [Server thread/WARN]:     /usr/local/gpx/users/user/127.0.0.1:25702/plugins/debug/DebugClass.java:2: error: package net.nowcraft.core.RuntimeCompiler does not exist
[14:04:10] [Server thread/WARN]: import net.nowcraft.core.RuntimeCompiler.Debugger
[14:04:10] [Server thread/WARN]:                                         
[14:04:10] [Server thread/WARN]: /usr/local/gpx/users/user/127.0.0.1:25702/plugins/debug/DebugClass.java:7: error: method does not override or implement a method from a supertype
[14:04:10] [Server thread/WARN]:     @Override
[14:04:10] [Server thread/WARN]:     ^
[14:04:10] [Server thread/WARN]: 3 errors
[14:04:10] [Server thread/ERROR]: null
org.bukkit.command.CommandException: Unhandled exception executing command 'rd' in plugin NowCraftCore v1.0
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[spigot.jar:git-Spigot-330d66b-fe41b01]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) ~[spigot.jar:git-Spigot-330d66b-fe41b01]
at org.bukkit.craftbukkit.v1_8_R1.CraftServer.dispatchCommand(CraftServer.java:642) ~[spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.PlayerConnection.handleCommand(PlayerConnection.java:1115) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.PlayerConnection.a(PlayerConnection.java:950) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.PacketPlayInChat.a(PacketPlayInChat.java:26) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.PacketPlayInChat.a(PacketPlayInChat.java:53) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.PacketHandleTask.run(SourceFile:13) [spigot.jar:git-Spigot-330d66b-fe41b01]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_25]
at net.minecraft.server.v1_8_R1.MinecraftServer.z(MinecraftServer.java:683) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.DedicatedServer.z(DedicatedServer.java:316) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.MinecraftServer.y(MinecraftServer.java:623) [spigot.jar:git-Spigot-330d66b-fe41b01]
at net.minecraft.server.v1_8_R1.MinecraftServer.run(MinecraftServer.java:526) [spigot.jar:git-Spigot-330d66b-fe41b01]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_25]

Caused by: java.lang.NullPointerException
at net.nowcraft.core.RuntimeCompiler.RuntimeCompiler.load(RuntimeCompiler.java:127) ~[?:?]
at net.nowcraft.core.RuntimeCompiler.RuntimeCompiler.loadHastebin(RuntimeCompiler.java:88) ~[?:?]
at net.nowcraft.core.RuntimeCompiler.RuntimeCompiler.debugFromHastebin(RuntimeCompiler.java:170) ~[?:?]
at net.nowcraft.core.commands.RuntimeDebug.onCommand(RuntimeDebug.java:35) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[spigot.jar:git-Spigot-330d66b-fe41b01]
... 14 more

РЕДАКТИРОВАТЬ: я также проверил его в другом каталоге, не работает. Однако, когда я использую код на своем локальном ноутбуке с Windows, он работает.

РЕДАКТИРОВАТЬ 2: Кажется, это проблема с CentOS, поскольку она не работает и во второй системе CentOS.


person Joba    schedule 22.12.2014    source источник
comment
Можете ли вы опубликовать трассировку стека?   -  person avgvstvs    schedule 22.12.2014
comment
Вы проверили, что зависимые классы на самом деле можно найти в пути к классам в системе, где происходит сбой компиляции? Кроме того, проверили ли вы, что проблемная система имеет ту же версию Java, что и успешный экземпляр?   -  person him    schedule 22.12.2014
comment
@avgvstvs Да, у них одинаковая версия Java (1.8), и я отредактировал основной пост с трассировкой стека.   -  person Joba    schedule 22.12.2014
comment
У меня есть половина мысли предположить, что, возможно, javac не может разрешить сетевую ссылку в указанном вами URL-адресе. Попробуйте использовать не сетевое расположение для файлов lib, то есть просто поместите их в папку lib относительно каталога, из которого вы строите.   -  person avgvstvs    schedule 23.12.2014
comment
Это не сетевое расположение, это каталог, который называется 127.0.0.1:25702.   -  person Joba    schedule 23.12.2014
comment
Я также проверил его в другом каталоге, не работает. Однако, когда я использую код на своем локальном ноутбуке с Windows, он работает.   -  person Joba    schedule 23.12.2014


Ответы (2)


Stacktrace очень помог, как и окружающий контекст.

Тут дело в линуксе. Итак, каталог, в который вы пытаетесь попасть:

/usr/local/gpx/users/user/127.0.0.1:25702/plugins/debug/DebugClass.java

БУКВАЛЬНО ищет каталог с именем 127.0.0.1:25702 (хотя : придется экранировать, потому что большинство оболочек используют : в качестве синтаксического символа.

Ваш сетевой адрес будет привязан к определенному каталогу. Вам нужно будет создать общий сетевой ресурс (не знаком с CentOS, но обычно это довольно просто), чтобы исключить сетевую ссылку на физически существующее местоположение. Если вы можете cd к нему из командной строки, то ваша среда выполнения Java должна иметь возможность ссылаться на него.

Вот ссылка для монтирования удаленных файловых систем в CentOS. Да, я знаю, что 127.0.0.1:25702 технически является «localhost», но ни командная оболочка, ни среда выполнения java не будут знать, как разрешить сетевой адрес так, как вы хотите сделать это здесь. Это работает в Windows, потому что Windows API более снисходительны.

person avgvstvs    schedule 06.01.2015

Я предполагаю, что вы используете Windows локально и Unix для удаленного сервера? разделитель пути к классам для java на машине unix - «:», и у вас есть каталог с «:» в имени, компилятор unix может разбивать имя каталога на «:». Вы пытались использовать путь к классам на нерабочей машине, который не включает «:» в именах файлов/каталогов?

person cmparish    schedule 23.12.2014
comment
Хорошо, это немного помогло. Я компилирую и выполняю классы, которым не нужны внешние библиотеки (они реализуют интерфейс отладчика из моего приложения). Я пытался использовать внешнюю библиотеку, но получаю новую ошибку: Exception in thread "main" java.lang.NoClassDefFoundError: com/mongodb/MongoClient Мой путь к классам: /home/user/DebugTester.jar:/home/user/mongo-java-driver-2.11.2.jar - person Joba; 23.12.2014
comment
пара вещей... 1) попробуйте поместить оператор отладки в buildclasspath, чтобы увидеть, что он возвращает. 2) просматривая код (не уверен, что не тестировал), но pluginDirectory может уже иметь / в конце ... поэтому добавление /* может добавить дополнительный /. - person cmparish; 23.12.2014
comment
Возможно, это было недостаточно ясно, извините. Проверьте мой первый ответ, Мой путь к классам: это то, что вернул метод. - person Joba; 23.12.2014
comment
хм, это интересно .. и я предполагаю, что пользователь ОС, на котором работает код, имеет доступ для чтения к /home/user и двум файлам jar? - person cmparish; 23.12.2014
comment
Да, это так. Вам нужен полный код, чтобы вы могли протестировать его самостоятельно? - person Joba; 23.12.2014
comment
Похоже, это какой-то плагин, верно? когда вы говорите, что он работает с вашего компьютера, вы запускаете его как плагин в том же приложении, в котором вы его развертываете, или вы запускаете его в автономном отладчике, когда запускаете его локально? - person cmparish; 24.12.2014
comment
Я запускаю оба в автономных отладчиках, но изначально это плагин. Этот плагин отлично работает на других серверах и на моем локальном компьютере. - person Joba; 25.12.2014