例外儿童服务在启动Optaplanner应用程序时没有父项

问题描述:

我有一个使用optaplanner的测试程序。没有直接使用KIE A​​PI,但它看起来像在幕后调用。这可能与我使用DROOLS进行分数计算有关。该程序从IDE或maven工作,但我想创建一个独立的jar,不需要maven。 我使用maven程序集插件来构建一个包含所有依赖包的独立运行的胖jar包。例外儿童服务在启动Optaplanner应用程序时没有父项

当我运行java -jar target/OptaPlannerTest-1.4-SNAPSHOT-jar-with-dependencies.jar我得到:

Exception in thread "main" java.lang.ExceptionInInitializerError 
     at org.kie.api.internal.utils.ServiceRegistry.getInstance(ServiceRegistry.java:27) 
     at org.kie.api.KieServices$Factory$LazyHolder.<clinit>(KieServices.java:332) 
     at org.kie.api.KieServices$Factory.get(KieServices.java:339) 
     at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:460) 
     at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331) 
     at org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220) 
     at org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:61) 
     at com.github.wshackle.optaplannertest.Main.main(Main.java:38) 
Caused by: java.lang.RuntimeException: Child services [org.kie.api.internal.assembler.KieAssemblers] have no parent 
     at org.kie.api.internal.utils.ServiceDiscoveryImpl.buildMap(ServiceDiscoveryImpl.java:186) 
     at org.kie.api.internal.utils.ServiceDiscoveryImpl.getServices(ServiceDiscoveryImpl.java:97) 
     at org.kie.api.internal.utils.ServiceRegistryImpl.<init>(ServiceRegistryImpl.java:36) 
     at org.kie.api.internal.utils.ServiceRegistryImpl$LazyHolder.<clinit>(ServiceRegistryImpl.java:32) 

线Main.java的38只两行到应用程序中,因此所有它做的加载配置文件,并尝试建立求解。

SolverFactory<Plan> solverFactory = SolverFactory.createFromXmlResource(
      "com/github/wshackle/optaplannertest/solverConfig.xml"); 
    Solver<Plan> solver = solverFactory.buildSolver(); 

solverConfig.xml是:

<solver> 
    <!-- Domain model configuration --> 
    <scanAnnotatedClasses> 
    <packageInclude>com.github.wshackle.optaplannertest.model</packageInclude> 
    </scanAnnotatedClasses> 


    <!-- Score configuration --> 
    <scoreDirectorFactory> 
     <scoreDrl>com/github/wshackle/optaplannertest/scoreRules.drl</scoreDrl> 
    </scoreDirectorFactory> 

    <!-- Optimization algorithms configuration --> 
    <termination> 
    <secondsSpentLimit>5</secondsSpentLimit> 
    </termination> 
</solver> 

在投是有关我的聚甲醛是这样的:

<?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"> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>com.github.wshackle</groupId> 
    <artifactId>OptaPlannerTest</artifactId> 
    <version>1.4-SNAPSHOT</version> 
    <packaging>jar</packaging> 
    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <maven.compiler.source>1.8</maven.compiler.source> 
     <maven.compiler.target>1.8</maven.compiler.target> 
     <optiplanner.version>7.3.0.Final</optiplanner.version> 
     <main.class>com.github.wshackle.optaplannertest.Main</main.class> 
    </properties> 
    <dependencies> 
     <dependency> 
      <groupId>org.optaplanner</groupId> 
      <artifactId>optaplanner-core</artifactId> 
      <version>${optiplanner.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.kie</groupId> 
      <artifactId>kie-api</artifactId> 
      <version>${optiplanner.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-api</artifactId> 
      <version>1.7.25</version> 
     </dependency> 
     <dependency> 
      <groupId>ch.qos.logback</groupId> 
      <artifactId>logback-classic</artifactId> 
      <scope>runtime</scope> 
      <version>1.2.3</version> 
     </dependency> 
    </dependencies> 
    <build> 
     <plugins> 
      <plugin> 
       <artifactId>maven-assembly-plugin</artifactId> 
       <version>2.5.5</version> 
       <configuration> 
        <archive> 
         <manifest> 
          <mainClass>${main.class}</mainClass> 
         </manifest> 
        </archive> 
        <descriptorRefs> 
         <descriptorRef>jar-with-dependencies</descriptorRef> 
        </descriptorRefs> 
       </configuration> 
       <executions> 
        <execution> 
         <id>make-assembly</id> <!-- this is used for inheritance merges --> 
         <phase>package</phase> <!-- bind to the packaging phase --> 
         <goals> 
          <goal>single</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

文件的罐中的完整列表显示在 https://gist.github.com/wshackle/8887aac8a10e8c4b1f862a4bda288e41

我用grep来验证他们似乎包括预期的cl驴每个罐子扶养:

> grep -c org/kie/api jarlisting.txt 
391 
> grep -c org/kie/internal jarlisting.txt 
364 
> grep -c org/optaplanner/core jarlisting.txt 
841 
> grep -c org/drools/core jarlisting.txt 
2175 
> grep -c org/drools/compiler jarlisting.txt 
832 
+0

这从您的IDE工作,对吧?在IDE中它没有做任何胖子的魔法。 –

+0

@GeoffreyDeSmet对。我相信IDE使用一个长类路径,其中包含一个带有裸类文件而不是JAR的目录。不幸的是,要区分JAR中包含的内容和类路径中的内容之间的区别并不容易,或者即使是这个问题也是不容易的。 – WillShackleford

+0

[相关jira](https://issues.jboss.org/browse/DROOLS-1761)链接到其他2个类似的问题。 –

的问题是,下面的jar文件都包含不同版本的META-INF/kie.conf

optaplanner-core-7.3.0.Final.jar 
kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar 
drools-core-7.3.0.Final.jar 
drools-compiler-7.3.0.Final.jar 

当Maven的组装插件把它们一起META-INF/kie.conf只有一个版本可以被包括在内。当建立求解器时,Optaplanner库将在当前的线程上下文类加载器上间接调用getResources("META-INF/kie.conf")。如果类路径中有多个jar,则会找到所有这些jar,并且生成的配置将是解析所有这些jar的产品。为了使这个工作在一个简单的超级jar文件中,需要将kie.conf文件移动到不同的文件名中,并重载一个类加载器以指导库以新名称使用它们。 (它可能还可以将它们组合成一个单一的文件kie.conf)

提取和移动kie.conf文件:

jar -xf ~/.m2/repository/org/optaplanner/optaplanner-core/7.3.0.Final/optaplanner-core-7.3.0.Final.jar META-INF/kie.conf 
mv META-INF/kie.conf src/main/resources/optaplanner-core-kie.conf 
jar -xf ~/.m2/repository/org/kie/kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar META-INF/kie.conf 
mv META-INF/kie.conf src/main/resources/kie-internal-kie.conf 
jar -xf ~/.m2/repository/org/drools/drools-core/7.3.0.Final/drools-core-7.3.0.Final.jar META-INF/kie.conf 
mv META-INF/kie.conf src/main/resources/drools-core-kie.conf 
jar -xf ~/.m2/repository/org/drools/drools-compiler/7.3.0.Final/drools-compiler-7.3.0.Final.jar META-INF/kie.conf 
mv META-INF/kie.conf src/main/resources/drools-compiler-kie.conf 

然后超载和设置线程上下文加载。

ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); 
    URL[] localKieConfUrls = new URL[]{ 
     ClassLoader.getSystemResource("optaplanner-core-kie.conf"), 
     ClassLoader.getSystemResource("kie-internal-kie.conf"), 
     ClassLoader.getSystemResource("drools-core-kie.conf"), 
     ClassLoader.getSystemResource("drools-compiler-kie.conf") 
    }; 
    ClassLoader newClassLoader = new ClassLoader(oldClassLoader) { 

     private final URL[] kieConfUrls = localKieConfUrls; 
     @Override 
     public Enumeration<URL> getResources(String name) throws IOException { 
      if ("META-INF/kie.conf".equals(name)) { 
       return new Enumeration<URL>() { 
        int index; 
        @Override 
        public boolean hasMoreElements() { 
         return index < kieConfUrls.length; 
        } 

        @Override 
        public URL nextElement() { 
         return kieConfUrls[index++]; 
        } 
       }; 
      } 
      return super.getResources(name); 
     } 

    }; 
    Thread.currentThread().setContextClassLoader(newClassLoader); 

运行“命令mvn依赖:树”,你会看到optaplanner核心取决于纪伊的API,纪伊内部的API,流口水核和滴料编译器。其中一个将会在你的胖罐子里失踪。

+0

我添加了问题的文件列表链接。所有的依赖似乎都在那里。 – WillShackleford

我是有以下POM

<?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"> 
    <modelVersion>4.0.0</modelVersion> 
.. 
    <dependencies> 
     <dependency> 
      <groupId>org.optaplanner</groupId> 
      <artifactId>optaplanner-core</artifactId> 
      <version>${optaPlanner.version}</version> 
     </dependency>  
... 
    </dependencies> 
    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-jar-plugin</artifactId> 
       <version>${jar.plugin.version}</version> 
       <configuration> 
        <archive> 
         <addMavenDescriptor>false</addMavenDescriptor> 
         <compress>false</compress>     
         <manifest> 
          <addClasspath>true</addClasspath> 
          <classpathPrefix>libs/</classpathPrefix> 
          <mainClass>${mainClass}</mainClass> 
         </manifest> 
         <index>true</index> 
         <manifestEntries> 
          <impl-version>${project.version}</impl-version> 
         </manifestEntries> 
        </archive> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-dependency-plugin</artifactId> 
       <version>${dependency.plugin.version}</version> 
       <executions> 
        <execution> 
         <id>copy-dependencies</id> 
         <phase>package</phase> 
         <goals> 
          <goal>copy-dependencies</goal> 
         </goals> 
         <configuration> 
          <outputDirectory>${project.build.directory}/libs</outputDirectory> 
         </configuration> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-assembly-plugin</artifactId> 
       <version>${assembly.plugin.version}</version> 
       <configuration> 
        <descriptors> 
         <descriptor>assembly/release.xml</descriptor> 
        </descriptors> 
        <finalName>${distribution.file.name}</finalName> 
        <outputDirectory>${project.build.directory}/dist</outputDirectory> 
        <workDirectory>${project.build.directory}/assembly/work</workDirectory> 
       </configuration> 
       <executions> 
        <execution> 
         <id>make-assembly</id> 
         <phase>package</phase> 
         <goals> 
          <goal>single</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

删除

<index>true</index> 

解决我的问题同样的问题。希望这可以帮助其他人。