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:
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.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331)
org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220)
org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:57)
org.optaplanner.EmployeeRoster.main(EmployeeRoster.java:31)
This is my line 31 in EmployeeRoster:
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
<?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:
<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?
Advertisement
Answer
For me, the issue had to deal with how I wanted to run the jar (java -jar), and consequently how I built the jar. The NullPointerException arose when I upgraded to optaplanner-core/7.4.1 from 6.4.0. This issue was not present back when I was still using 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.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:503)
The following is a temporary workaround I did to resolve the NullPointerException and just get the application to run.
- Use IntelliJ’s gradle to build one big jar with all dependencies.
- Unzip the jar, for example, to unzippedJar/ directory.
- Modify unzippedJar/META-INF/kie.conf
- Rejar the files.
- Run the jar with java.
Step 1. Building the 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
unzip fatJar.jar -d unzippedJar/
Step 3. Modify kie.conf
The “fatJar” task flattened the dependencies – duplicate file names are allowed in the jar. This resulted in four unzippedJar/META-INF/kie.conf files, only one of which was used. Regardless of whichever kie.conf file was used, this was my final 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
For whatever reason, specifying the MANIFEST.MF file did nothing for me, hence I left it out.
jar cf rejard.jar .
Step 5. Run the jar
java -cp rejard.jar path.to.class.with.main.method