Я хочу выполнить одну java-программу из моего текущего java-проекта. У него есть несколько зависимостей jar, которые следует добавить в путь к классам перед его выполнением. Сначала я попытался выполнить с помощью обычной команды java -

  String classDir = "";
  for (int i = 0; i < compilerConfiguration.getClasspathEntries().size(); i++) {
        classDir = classDir + compilerConfiguration.getClasspathEntries().get(i) + ";";
  }
  runProcess("java -cp " + classDir + " topLevelProject.com.test.project.App");

  private static void runProcess(String command) throws Exception {
    Process pro = Runtime.getRuntime().exec(command);
    printLines(command + " stdout:", pro.getInputStream());
    printLines(command + " stderr:", pro.getErrorStream());
    pro.waitFor();
    System.out.println(command + " exitValue() " + pro.exitValue());
  } 

Но поскольку есть несколько записей пути к классам, это дает мне ошибку -

  java.io.IOException: Cannot run program "java": CreateProcess error=206, The filename or extension is too long

Содержимое classDir примерно такое -

E:\test\maven\com.test.project\target\classes;C:\Users\dd\.m2\repository\p2\osgi\bundle\com.t.cep.studio.cli\5.3.0.164\com.t.cep.studio.cli-5.3.0.164.jar[+com/t/cep/studio/cli/studiotools/*;?**/*];C:\Users\dd\.m2\repository\p2\osgi\bundle\org.eclipse.core.runtime\3.11.1.v20150903-1804\org.eclipse.core.runtime-3.11.1.v20150903-1804.jar[~org/eclipse/core/internal/preferences/legacy/*;~org/eclipse/core/internal/runtime/*;+org/eclipse/core/runtime/*;?**/*];

В качестве альтернативы я попытался динамически установить путь к классам перед выполнением команды java:

  try {
        for (int i = 0; i < compilerConfiguration.getClasspathEntries().size(); i++) {
            String filePath = "file://" + compilerConfiguration.getClasspathEntries().get(i);
            URL[] url = { new URL(filePath) };
            ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
            URLClassLoader urlClassLoader = new URLClassLoader(url, currentThreadClassLoader);
            Thread.currentThread().setContextClassLoader(urlClassLoader);
        }
        runProcess("java  topLevelProject.com.test.project.App");
    } catch (Exception e) {
        e.printStackTrace();
    }  

Но он не устанавливает путь к классам, как ожидалось. Любой другой обходной путь?

2
Disha 8 Сен 2016 в 09:51

3 ответа

Лучший ответ

В дополнение к ответу @Szmeby, если вы не знаете, как использовать файл с путем к классам внутри, вы можете попытаться создать «банку пути».

"Путь jar" содержит только файл Manifest.mf, который включает следующую запись:

Class-Path: some.jar another.jar others.jar

Вы также можете использовать подстановочные знаки для уменьшения длины.

3
Lostboy 12 Сен 2016 в 15:27

Еще одно решение для запуска Java-приложения из Java - использование загрузчика классов. Это дает следующие преимущества:

  • Вы можете гарантировать, что новая программа будет работать с той же версией Java, что и ваша программа, что устраняет проблему с несколькими установками.
  • Новая программа может более легко взаимодействовать с вашей программой, если вы этого захотите (хотя это совсем не обязательно, если вы выберете этот маршрут).
  • Он более независим от платформы в том смысле, что любая установка со странной конфигурацией командной строки не является проблемой.

Чтобы использовать это решение, просто загрузите все необходимые jar-файлы с помощью URLClassLoader, а затем вызовите основной метод через отражение:

URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{
    new URL("file://path/to/jar/1.jar"),
    new URL("file://path/to/jar/2.jar"),
    new URL("file://path/to/jar/3.jar"),
    new URL("file://path/to/jar/4.jar"),
    new URL("file://path/to/jar/5.jar")
});

Class<?> clazz = urlClassLoader.loadClass("topLevelProject.com.test.project.App");
clazz.getMethod("main", String[].class).invoke(null, new String[]{"Command", "Line", "Arguments", "Here"});
1
john01dav 12 Сен 2016 в 22:16

Я думаю, что это в основном проблема ОС, вызванная ограничением длины командной строки, а не java. У меня была такая же проблема, когда я играл с jdeps, для этого также требовался огромный путь к классам. В конце концов я экспортировал путь к классам в простой текстовый файл и вложил содержимое этого файла в качестве аргумента команды.

Предполагая, что имя текстового файла, содержащего строку пути к классам: cp.txt

Его содержание (частично):

/home/anon/.m2/repository/com/app/generator/2.0.jar:/home/anon/.m2/repository/com/app/model/2.0.jar:/home/anon/.m2/repository/com/generator-helpers/2.0.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.ecore/2.10.1-v20140901-1043/org.eclipse.emf.ecore-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.common/2.10.1-v20140901-1043/org.eclipse.emf.common-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.ecore.xmi/2.10.1-v20140901-1043/org.eclipse.emf.ecore.xmi-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/commons-io/commons-io/2.1/commons-io-2.1.jar:etc...

Затем вы должны выполнить свою команду так:

runProcess("java -cp $(< cp.txt) topLevelProject.com.test.project.App");

Он может использовать строку пути к классам любого размера, однако это решение только для Linux . Я не знаю, как встроить содержимое файла в командную строку Windows. Что ж, по крайней мере, я надеюсь, что это дает вам идею двигаться дальше.

1
Szmeby 12 Сен 2016 в 12:36