Spring boot OptaPlanner';s流口水规则不';t使用弹簧靴点火';s在类路径上开发工具,因此分数为零

Spring boot OptaPlanner';s流口水规则不';t使用弹簧靴点火';s在类路径上开发工具,因此分数为零,spring-boot,drools,optaplanner,Spring Boot,Drools,Optaplanner,我让optaplanner按照drools规则正常工作。 “突然”,在我做了一些改变之后,Optaplanner不再把我的事实放在drools kSession中 我做了一些日志记录,我看到optaplanner对我的解决方案调用了getProblemFacts()方法,这个方法返回一个大小大于0的列表 我编写了一个DRL规则来简单地计算事实并记录这些计数(该规则经过单元测试,在我自己将对象放入ksession时效果很好)。我还确信optaplanner不会将事实记录在工作记忆中 Constru

我让optaplanner按照drools规则正常工作。 “突然”,在我做了一些改变之后,Optaplanner不再把我的事实放在drools kSession中

我做了一些日志记录,我看到optaplanner对我的解决方案调用了getProblemFacts()方法,这个方法返回一个大小大于0的列表

我编写了一个DRL规则来简单地计算事实并记录这些计数(该规则经过单元测试,在我自己将对象放入ksession时效果很好)。我还确信optaplanner不会将事实记录在工作记忆中

ConstructionHeuristics阶段结束得很好(并且完成了它的工作,因为我的规划变量在此阶段之后不再为空)。我只有在本地搜索开始时才收到问题

不知道如何/在何处进一步搜索以了解问题。有什么想法吗

我有一个建议:我使用
,并且有这个问题。 如果我使用
将这两个类“手动”放置,则会得到一个反射错误:

Exception in thread "Solver" java.lang.IllegalArgumentException: object is not an instance of declaring class
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.optaplanner.core.impl.domain.common.accessor.BeanPropertyMemberAccessor.executeGetter(BeanPropertyMemberAccessor.java:67)
    at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.extractEntityCollection(SolutionDescriptor.java:626)
    at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getEntityCount(SolutionDescriptor.java:489)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner$FieldAccessingSolutionClonerRun.cloneSolution(FieldAccessingSolutionCloner.java:200)
    at org.optaplanner.core.impl.domain.solution.cloner.FieldAccessingSolutionCloner.cloneSolution(FieldAccessingSolutionCloner.java:70)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:147)
    at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:197)
    at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:195)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:175)
    at ****.services.impl.SolverServiceImpl.lambda$0(SolverServiceImpl.java:169)
在我的应用程序中,我到处都有一个
org.springframework.boot.devtools.restart.classloader.RestartClassLoader

这不是默认的类装入器,因此类装入的魔力正在发挥。根据您的评论,它与用于加载optaplanner类的类加载器不同。因此,您需要提供类加载器:

Classloader classloader = TimeTable.class.getClassLoader();
... = SolverFactory.createFromXmlResource(".../solverConfig.xml", classloader);

可能需要升级到
6.4.0.Beta2
,上个月我已经修复了一些高级类加载问题。

我正在使用spring开发工具自动重新加载源文件中的webapp uppon更改


org.springframework.boot

所以我的问题不是很好。Drools工作内存不是空的,但包含的对象不是我的类的
实例,因为不在同一个类加载器中

为了理解这一点,我使用了以下规则:

rule "countProblemFacts"
when
    $nLectures : Long() from accumulate($lectures : Lecture(), count( $lectures ))
    $nCourses : Long() from accumulate($courses : Course(), count( $courses ))
    $nRooms : Long() from accumulate($rooms : Room(), count( $rooms ))
    $nPeriods : Long() from accumulate($periods : Period(), count( $periods ))
    $nObjects : Long() from accumulate($objects : Object(), count( $objects ))
then
    DroolsUtil.log(drools, "Drools working memory");    
    DroolsUtil.log("Lectures:", $nLectures);
    DroolsUtil.log("Courses:", $nCourses);
    DroolsUtil.log("Rooms:", $nRooms);
    DroolsUtil.log("Periods:", $nPeriods);
    DroolsUtil.log("Objects:", $nObjects);
    DroolsUtil.log(drools, "Total", ($nLectures + $nCourses + $nRooms + $nPeriods), "objects");
end

$nObjects计数为12,其他所有对象计数为0,因为类不“相同”。

该问题应在Drools 7.23.0.Final中解决。请参阅。

最后一个异常非常奇怪。在
BeanPropertyMemberAccessor.executeGetter()
中放置一个断点,并打印出
propertyType
bean.getClass()
在这里,我想更好地理解错误配置,以便optaplanner可以抛出更好的错误消息。至于您最初的问题,在DroolsScoreDirector#resetKieSession中放置一个调试断点,并跟踪getWorkingFacts(即getProblemFacts()和规划实体)的轨迹。您是否执行了任何类加载魔术,如OSGi?不,这里没有魔术。我在Spring boot tomcat容器中使用6.3.0-final。我以前就让它工作过,所以类加载是可以的。是的,
bean.getClass().getName()==timeline.class.getName()
返回
true
。但是没有,使用
bean.getClass().getClassLoader()==timeline.class.getClassLoader()
我看到了两个不同的类加载器。我应该确保它们是相同的吗?我更新到6.4.0.Beta2,并使用了这个代码片段。但是我仍然在
BeanPropertyMemberAccessor
中得到spring类加载器,在我的时间表类中得到
sun.misc.Launcher.AppClassLoader
。疯子无论如何,我认为这不是问题所在,因为
resetKieSession
获得了正确的
workingFacts
集合,包含所有事实和规划实体,并且我看到所有需要调用
kieSession.insert()
。我的规则仍然一无所获。也许这就是规则——简化它,这样就不可能在规划实体上不匹配。如果你仍然能理解,请把它添加到问题中。但是类加载问题让我更感兴趣。指定
应始终有效。事实上,
在某些环境中是非常不受欢迎的(比如JDK 9 Jigsaw等)。所以我想复制这个问题-有没有可能用一个复制机来复制呢?这是正确的解决方案。不管怎样,按照我的回答中所描述的那样使用类加载器可能是个好主意,因为它修复了Spring Boot的另一个相关问题。