简体   繁体   English

Optaplanner - 创建 jar 文件时出现 NullPointerException

[英]Optaplanner - NullPointerException when creating jar file

My program works fine from my IDE (IntelliJ) but for some reason, when I try to create a jar file I get following error when I run the program from a terminal:我的程序在我的 IDE (IntelliJ) 上运行良好,但由于某种原因,当我尝试创建一个 jar 文件时,当我从终端运行程序时出现以下错误:

Exception in thread "main" java.lang.NullPointerException at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:461) org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:461) 处的线程“main”java.lang.NullPointerException 中的异常

org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331) org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331)

org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220) org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220)

org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:57) org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:57)

org.optaplanner.EmployeeRoster.main(EmployeeRoster.java:31) org.optaplanner.EmployeeRoster.main(EmployeeRoster.java:31)

This is my line 31 in EmployeeRoster:这是我在 EmployeeRoster 中的第 31 行:

Solver solver = SolverFactory.createFromXmlResource(SOLVER_CONFIG_XML).buildSolver();

SOLVER_CONFIG_XML is a String containing my path for my XML solver-config, it looks like this SOLVER_CONFIG_XML 是一个包含我的 XML 求解器配置路径的字符串,它看起来像这样

 <?xml version="1.0" encoding="UTF-8"?> <solver> <solutionClass>org.optaplanner.solver.Roster</solutionClass> <entityClass>org.optaplanner.domain.Assignment</entityClass> <scoreDirectorFactory> <scoreDrl>org/optaplanner/solver/employeeShiftsScoreRules.drl</scoreDrl> </scoreDirectorFactory> <localSearch> <termination> <secondsSpentLimit>5</secondsSpentLimit> <bestScoreLimit>0hard/0medium/0soft</bestScoreLimit> </termination> <!--<termination> <unimprovedStepCountLimit>5</unimprovedStepCountLimit> </termination>--> <acceptor> <entityTabuSize>7</entityTabuSize> </acceptor> <forager> <acceptedCountLimit>1000</acceptedCountLimit> </forager> </localSearch> </solver>

Also here's my pom.xml file if that should be relevant:如果应该相关,这里还有我的 pom.xml 文件:

<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>org.btrg.dfb</groupId>
<artifactId>optaplanner</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
    <dependency>
        <groupId>org.optaplanner</groupId>
        <artifactId>optaplanner-core</artifactId>
        <version>7.3.0.Final</version>
    </dependency>

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.8</version>
    </dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.1</version>
    </dependency>

    <dependency>
        <groupId>com.jolira</groupId>
        <artifactId>onejar-maven-plugin</artifactId>
        <version>1.4.4</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>

        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>org.avalin.optaplanner.EmployeeRoster</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-my-jar-with-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>one-jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

What might I be doing wrong?我可能做错了什么?

For me, the issue had to deal with how I wanted to run the jar ( java -jar ), and consequently how I built the jar.对我来说,这个问题必须处理我想如何运行 jar ( java -jar ),以及我如何构建 jar。 The NullPointerException arose when I upgraded to optaplanner-core/7.4.1 from 6.4.0 .当我从6.4.0升级到optaplanner-core/7.4.1时出现 NullPointerException 。 This issue was not present back when I was still using 6.4.0.当我还在使用 6.4.0 时,这个问题就不存在了。

Exception:例外:

java.lang.NullPointerException at org.kie.internal.io.ResourceFactory.newByteArrayResource(ResourceFactory.java:66) at org.drools.compiler.kie.builder.impl.AbstractKieModule.getResource(AbstractKieModule.java:299) at org.drools.compiler.kie.builder.impl.AbstractKieModule.addResourceToCompiler(AbstractKieModule.java:264) at org.drools.compiler.kie.builder.impl.AbstractKieModule.addResourceToCompiler(AbstractKieModule.java:259) at org.drools.compiler.kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:243) at org.drools.compiler.kie.builder.impl.AbstractKieProject.verify(AbstractKieProject.java:74) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildKieProject(KieBuilderImpl.java:250) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:218) at org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:176) at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDi java.lang.NullPointerException at org.kie.internal.io.ResourceFactory.newByteArrayResource(ResourceFactory.java:66) at org.drools.compiler.kie.builder.impl.AbstractKieModule.getResource(AbstractKieModule.java:299) at org. drools.compiler.kie.builder.impl.AbstractKieModule.addResourceToCompiler(AbstractKieModule.java:264) at org.drools.compiler.kie.builder.impl.AbstractKieModule.addResourceToCompiler(AbstractKieModule.java:259) at org.drools kie.builder.impl.AbstractKieProject.buildKnowledgePackages(AbstractKieProject.java:243) 在 org.drools.compiler.kie.builder.impl.AbstractKieProject.verify(AbstractKieProject.java:74) 在 org.drools.compiler.kie.builder。 impl.KieBuilderImpl.buildKieProject(KieBuilderImpl.java:250) 在 org.drools.compiler.kie.builder.impl.KieBuilderImpl.buildAll(KieBuilderImpl.java:218) 在 org.drools.compiler.kie.builder.impl.KieBuilderImpl。 buildAll(KieBuilderImpl.java:176) 在 org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDi rectorFactory(ScoreDirectorFactoryConfig.java:503) rectorFactory(ScoreDirectorFactoryConfig.java:503)

The following is a temporary workaround I did to resolve the NullPointerException and just get the application to run.以下是我为解决 NullPointerException 并让应用程序运行而执行的临时解决方法

  1. Use IntelliJ's gradle to build one big jar with all dependencies.使用 IntelliJ 的 gradle 构建一个包含所有依赖项的大 jar。
  2. Unzip the jar, for example, to unzippedJar/ directory.解压jar,例如解压unzippedJar/目录。
  3. Modify unzippedJar/META-INF/kie.conf修改unzippedJar/META-INF/kie.conf
  4. Rejar the files.重新打包文件。
  5. Run the jar with java.用java运行jar。

Step 1. Building the jar步骤 1. 构建 jar

dependencies {
    ...
    compile group: 'org.optaplanner', name: 'optaplanner-core', version:'7.4.1.Final'
    compile group: 'org.optaplanner', name: 'optaplanner-benchmark', version:'7.4.1.Final'
    ...
}
task fatJar(type: Jar) {
    manifest {
        attributes 'Implementation-Title': 'Self contained jar with all dependencies',
        'Implementation-Version': version,
        'Main-Class': 'path.to.class.with.main.method'
    }
    baseName = 'fatJar'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

Step 2. Unzip步骤 2. 解压缩

unzip fatJar.jar -d unzippedJar/

Step 3. Modify kie.conf第三步,修改kie.conf

The "fatJar" task flattened the dependencies - duplicate file names are allowed in the jar. “fatJar”任务扁平化了依赖关系——jar 中允许重复的文件名。 This resulted in four unzippedJar/META-INF/kie.conf files, only one of which was used.这导致了四个解压缩的 Jar/META-INF/kie.conf文件,其中只有一个被使用。 Regardless of whichever kie.conf file was used, this was my final kie.conf.无论使用哪个 kie.conf 文件,这都是我最后的 kie.conf。

    org.kie.api.internal.assembler.KieAssemblers = +org.optaplanner.core.impl.solver.kie.KieSolverAssemblerService
    org.kie.api.internal.assembler.KieAssemblers = org.kie.internal.services.KieAssemblersImpl
    org.kie.api.internal.runtime.KieRuntimes = org.kie.internal.services.KieRuntimesImpl
    org.kie.api.internal.weaver.KieWeavers = org.kie.internal.services.KieWeaversImpl
    org.kie.api.internal.runtime.beliefs.KieBeliefs = org.kie.internal.services.KieBeliefsImpl
    org.kie.api.io.KieResources = org.drools.core.io.impl.ResourceFactoryServiceImpl
    org.kie.api.marshalling.KieMarshallers = org.drools.core.marshalling.impl.MarshallerProviderImpl
    org.kie.api.concurrent.KieExecutors = org.drools.core.concurrent.ExecutorProviderImpl
    org.kie.api.KieServices = org.drools.compiler.kie.builder.impl.KieServicesImpl
    org.kie.internal.builder.KnowledgeBuilderFactoryService = org.drools.compiler.builder.impl.KnowledgeBuilderFactoryServiceImpl

Step 4. Rejar第 4 步。重新振作

For whatever reason, specifying the MANIFEST.MF file did nothing for me, hence I left it out.无论出于何种原因,指定 MANIFEST.MF 文件对我没有任何帮助,因此我将其排除在外。

jar cf rejard.jar .

Step 5. Run the jar步骤 5. 运行 jar

java -cp rejard.jar path.to.class.with.main.method

Following @Arturo W's answer, I can suggest another fix using maven's assembly plugin to make a fat jar.按照@Arturo W 的回答,我可以建议使用maven 的程序集插件制作一个胖罐子的另一个修复程序。

As stated in the documentation :文档中所述:

"If two or more elements (eg, file, fileSet) select different sources for the same file for archiving, only one of the source files will be archived. [...] The order of the phases is as follows: 1) FileItem 2) FileSets 3) ModuleSet 4) DependencySet and 5) Repository elements." “如果两个或多个元素(例如,file、fileSet)为同一文件选择不同的源进行归档,则只会归档其中一个源文件。[...] 阶段的顺序如下:1) FileItem 2) 文件集 3) 模块集 4) 依赖集和 5) 存储库元素。”

META-INF/kie.conf is provided in org.optaplanner.core 's archive, hence maven packages optaplanner's version over the custom one define in your repository. META-INF/kie.conforg.optaplanner.core的存档中提供,因此 maven 将 optaplanner 的版本封装在存储库中定义的自定义版本之上。

To include it, we exclude all META-INF/kie.conf files during unpackaging and manually copy our version using the <file></file> option in a custom descriptor file.为了包含它,我们在解包过程中排除了所有META-INF/kie.conf文件,并使用自定义描述符文件中的<file></file>选项手动复制我们的版本。

Here's how we do it:这是我们如何做到的:

pom.xml 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">
    <!-- ... -->
    <build>
        <plugins>
            <!-- ... -->

            <!-- fat jar -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <descriptors>
                        <descriptor>src/assembly/distribution.xml</descriptor>
                    </descriptors>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.veryseriouscompany.veryseriousproject.app.Main</mainClass>
                        </manifest>
                    </archive>

                </configuration>
                <executions>
                    <execution>
                        <id>assemble-all</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <!-- ... -->

To fix the inclusion of kie.conf , we'll have to write a custom descriptor, defined in src/assembly/distribution.xml .要修复包含kie.conf ,我们必须编写一个自定义描述符,在src/assembly/distribution.xml定义。 We start from a predefined descriptor: jar-with-dependencies .我们从一个预定义的描述符开始: jar-with-dependencies That's a good starting point.这是一个很好的起点。

src/assembly/distribution.xml源代码/程序集/distribution.xml

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    <id>epigno-jar-with-dependencies</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
            <!-- Exclude all META-INF/kie.conf during unpacking -->
            <unpackOptions>
                <excludes>
                    <exclude>META-INF/kie.conf</exclude>
                </excludes>
            </unpackOptions>
        </dependencySet>
    </dependencySets>
    <files>
        <file>
            <!-- Manually copy your custom kie configuration file from your repository. -->
            <!-- Please replace this path by whatever path is relevant for your project. -->
            <source>src/main/resources/META-INF/kie.conf</source>
            <outputDirectory>META-INF</outputDirectory>
        </file>
    </files>
</assembly>

When you are finished, run完成后,运行

mvn package

Hopefully, this will package the correct kie.conf in your fat jar!希望这会将正确的kie.conf到您的胖 jar 中!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM