Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以替换Gradle用于运行Java的JavaExecution?_Java_Gradle - Fatal编程技术网

是否可以替换Gradle用于运行Java的JavaExecution?

是否可以替换Gradle用于运行Java的JavaExecution?,java,gradle,Java,Gradle,当类路径太长时,Java无法启动。窗户上的长度限制特别短 Gradle似乎对解决他们这边的问题不感兴趣(尽管这是他们的责任,因为他们是Java的始作俑者),所以我们最终用自己的替代方案取代了JavaExec任务 替代方案如下所示: public class WorkingJavaExec extends JavaExec { private static final String MATCH_CHUNKS_OF_70_CHARACTERS = "(?<=\\G.{7

当类路径太长时,Java无法启动。窗户上的长度限制特别短

Gradle似乎对解决他们这边的问题不感兴趣(尽管这是他们的责任,因为他们是Java的始作俑者),所以我们最终用自己的替代方案取代了
JavaExec
任务

替代方案如下所示:

public class WorkingJavaExec extends JavaExec {
    private static final String MATCH_CHUNKS_OF_70_CHARACTERS =
        "(?<=\\G.{70})";

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void exec() {
        FileCollection oldClasspath = getClasspath();
        File jarFile = null;
        try {
            if (!oldClasspath.isEmpty()) {
                try {
                    jarFile =
                        toJarWithClasspath(oldClasspath.getFiles());
                    setClasspath(getProject().files(jarFile));
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }

            super.exec();
        } finally {
            setClasspath(oldClasspath);

            if (jarFile != null) {
                try {
                    Files.delete(jarFile.toPath());
                } catch (Exception e) {
                    logger.warn("Couldn't delete: " + jarFile, e);
                }
            }
        }
    }

    public static File toJarWithClasspath(Set<File> files)
            throws IOException {
        File jarFile = File.createTempFile("long-classpath", ".jar");
        try (ZipOutputStream zip =
                new ZipOutputStream(new FileOutputStream(jarFile))) {
            zip.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
            try (PrintWriter writer =
                    new PrintWriter(
                        new OutputStreamWriter(
                            zip, StandardCharsets.UTF_8))) {
                writer.println("Manifest-Version: 1.0");
                String classPath = files.stream().map(
                        file -> file.toURI().toString())
                    .collect(Collectors.joining(" "));
                String classPathEntry = "Class-Path: " + classPath;
                writer.println(Arrays.stream(
                    classPathEntry.split(MATCH_CHUNKS_OF_70_CHARACTERS))
                    .collect(Collectors.joining("\n ")));
            }
        }
        return jarFile;
    }
}
public类WorkingJavaExec扩展了JavaExec{
私有静态最终字符串匹配\u块\u个字符=

(?您可以使用
jar
任务将类路径添加到清单中:

jar {
    baseName = "my-app"
    version =  "1.0.0"
    manifest {
        attributes("Class-Path": configurations.compile.collect { it.getName() }.join(' '))
    }
}
然后,您可以在启动时引用该jar:

task run(type:JavaExec) {
    classpath = jar.outputs.files
    main = "myapp.MainClass"
}
这可以绕过命令行路径限制。您可能还希望将依赖项jar复制到输出文件夹,以便它们在运行时可用

task copyDependencies(type: Copy, dependsOn: [ "build" ]) {
   from configurations.runtime
   into "./build/libs"
}

build.finalizedBy(copyDependencies)
有用吗?

我不确定您是否可以“替换”
JavaExecAction
,因为它是在JavaExec任务实例化期间设置的,但我认为您可以使用自定义的插件来更好地解决此问题,如下所示:

class FixClasspathLimitPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {

        // after project has been evaluated, hack into all tasks of type JavaExec declared.
        project.afterEvaluate {

            project.tasks.stream().filter { task -> task instanceof JavaExec }.forEach {
                println "Reconfiguring classpath for :  $it"
                JavaExec javaExec = (JavaExec) it;
                FileCollection oldClasspath = javaExec.getClasspath()

                // insert an Action at first position, that will change classpath
                javaExec.doFirst { task ->
                    ((JavaExec) task).setClasspath(getProject().files(toJarWithClasspath(oldClasspath.getFiles())));
                }
                // optional - reset old classpath
                javaExec.doLast { task ->
                    ((JavaExec) task).setClasspath(oldClasspath)
                }
            }
        }
    }

    public static File toJarWithClasspath(Set<File> files)
        throws Exception {

        // same method implementation as given in your question

    }
类FixClasspathLimitPlugin实现插件{
@凌驾
无效申请(项目){
//在对项目进行评估之后,侵入所有JavaExec类型的任务。
项目后评估{
project.tasks.stream().filter{task->task instanceof JavaExec}.forEach{
println“为$it重新配置类路径”
JavaExec-JavaExec=(JavaExec)it;
FileCollection oldClasspath=javaExec.getClasspath()
//在第一个位置插入将更改类路径的操作
javaExec.doFirst{task->
((JavaExec)task).setClasspath(getProject().files(toJarWithClasspath(oldclaspath.getFiles()));
}
//可选-重置旧类路径
javaExec.doLast{task->
((JavaExec)任务).setClasspath(oldClasspath)
}
}
}
}
公共静态文件toJarWithClasspath(设置文件)
抛出异常{
//与问题中给出的方法实现相同
}
这样,您就不必在团队编写的所有构建脚本中替换JavaExec,您只需确保这些脚本应用您的插件即可

如果您使用Gradle的自定义发行版并在企业中使用包装器,您甚至可以将此插件作为初始脚本包含在此发行版中,如下所述:

在gradle发行版的gradle_HOME/init.d/目录中放置一个以.gradle结尾的文件。这允许您打包一个包含一些自定义生成逻辑和插件的自定义gradle发行版。您可以将其与gradle包装器结合,以使自定义逻辑可用于企业中的所有生成

这样,插件将以“透明”的方式应用


关于
Test
任务:我认为它不使用
JavaExecAction
,但是可以应用类似的解决方案,使用类似的插件。

作为一个插件,我认为这肯定有一些优点,因为它减少了人们在包含解决方法时所需的工作量。它比just JavaExec,因为使用JavaExecAction的所有其他任务也需要更改,而且我不完全确定如何找出行为不端任务的完整列表:(另外,我认为如果我们要制作一个定制的Gradle发行版,最好的解决方案可能是修改JavaExecution本身,使其在不修改的情况下正常工作。我认为我将避免修改jar本身内部的类路径,因为一旦项目打包,路径将再次出错,而我在过去注意到即使您没有使用
java-jar
,JVM也会尝试解析类路径上的jar,这会减慢启动速度并产生不必要的警告。因此,如果我们制作一个单独的jar,并在其中包含解决方法,以避免修改最终分发的主jar,这种方法将最有效。