Spring boot OptaPlanner在Spring引导中出现java反射错误

Spring boot OptaPlanner在Spring引导中出现java反射错误,spring-boot,reflection,optaplanner,Spring Boot,Reflection,Optaplanner,我刚刚尝试在Spring Boot中运行OptaPlanner项目,但在OptaPlanner Spring用户指南中只有非常简单的文本 实际上,我认为将所有域对象、配置文件和drools文件从OptaPlanner项目复制到Spring Boot项目是非常容易的,而不做任何更改,但唯一的问题是如何调用Solver的solve方法 我让它在Spring启动后运行,并使用一个类(名为CommandLineAppStartupRunner)实现了CommandLineRunner接口,我在它的run

我刚刚尝试在Spring Boot中运行OptaPlanner项目,但在OptaPlanner Spring用户指南中只有非常简单的文本

实际上,我认为将所有域对象、配置文件和drools文件从OptaPlanner项目复制到Spring Boot项目是非常容易的,而不做任何更改,但唯一的问题是如何调用
Solver
solve
方法

我让它在Spring启动后运行,并使用一个类(名为
CommandLineAppStartupRunner
)实现了
CommandLineRunner
接口,我在它的
run
方法中调用了
solve
方法。最后,我得到一个例外,如下所示:

Caused by: java.lang.IllegalArgumentException: Can not set org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore field springbootcloudbalance.domain.CloudBalance.score to springbootcloudbalance.domain.CloudBalance
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at org.optaplanner.core.impl.domain.common.accessor.ReflectionFieldMemberAccessor.executeGetter(ReflectionFieldMemberAccessor.java:54)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getScore(SolutionDescriptor.java:1071)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:212)
at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:230)
at org.optaplanner.core.impl.solver.AbstractSolver.solvingStarted(AbstractSolver.java:75)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:210)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:190)
at springbootcloudbalance.CommandLineAppStartupRunner.run(CommandLineAppStartupRunner.java:55)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818)
... 10 common frames omitted
我检查了代码,发现异常抛出,因为
field.getDeclaringClass()
中的对象与
var1.getClass()
中的对象是不同的实例。恐怕这是由于OptaPlanner和Spring Boot之间的java反射实现冲突造成的

我使用的版本如下:

  • OptaPlanner 7.11.0.1决赛
  • 弹簧防尘套2.0.5.1版本
  • JVM 1.8.0_181

删除spring boot devtools依赖项可修复此错误。另一个与此类似的问题解释了它与不同的类加载器有关:。公认的答案还提到了一个可能的解决方案:

要修复此问题,请将spring dev工具配置为在RestartClassLoader中加载Drools库以及项目的类:


尼克的回答是正确的。这只是为了弄清楚发生了什么

此行表示optaplanner正在提取
CloudBalance.getScore()

这一行意味着它使用了一个
ReflectionFieldMemberAccessor
,这是通过反射读取字段(包括私有字段)的方法:

现在,错误消息是它变得有趣的地方:

Can not set ...HardMediumSoftScore field ...CloudBalance.score to ...CloudBalance
看起来基本上是这样:

CloudBalance cloudBalance2 = cloudBalance.getScore();

嗯?

穆萨提供了这个答案,但有人删除了它,尽管JIRA链接非常相关,因为它指出了哪个版本的OptaPlanner可以更好地处理这个问题:


“向OptaPlanner提交了一个问题,以便为此类情况提供更好的错误消息:。请随意添加任何评论或建议。”

Spring Boot和OptaPlanner完全能够协同工作,因此我猜这一定是您的代码中的某些内容。这将有助于查看更多的runner类和解决方案类。您好,您可以从中查看代码。此外,如果将OptaPlanner相关代码从
CommandLineAppStartupRunner
移动到
main
函数,这意味着它不是springboot应用程序,而是普通java应用程序,那么它工作正常。删除spring boot devtools依赖项为我修复了它,因此显然该依赖项确实会以某种方式干扰反射。我以前在自己的项目中看到过这一点。解释可能与此问题的公认答案相同:。另外,在使用dev-tools依赖项时,在XML配置中使用scannectedclass也可以使其工作(而不是手动定义解决方案和实体类)。我建议禁用它,因为问题已提交给OptaPlanner,以便为此类情况提供更好的错误消息:。请随意添加任何评论或建议。boot devtools的作用是什么?OptaPlanner和它真的应该是兼容的。我们很有兴趣知道如何允许这一点。我恐怕有一件事无法解释为什么
ScanAnnotatedClass
spring boot devtools
一起工作,但是
solutionClass
entityClass
不使用
spring boot devtools
使项目资源和库由分离类装入器。可能还有其他原因。。。
Can not set ...HardMediumSoftScore field ...CloudBalance.score to ...CloudBalance
CloudBalance cloudBalance2 = cloudBalance.getScore();