版本升级后例外

时间:2019-09-05 13:01:02

标签: java optaplanner

使用Optaplanner v7.11.0.Final的项目存在分数持久性问题,我升级到了最新版本(v7.25.0.Final),但出现以下异常:

The externalObject (Etat(super=DbObject(id=11), libelle=RCD, ordre=60)) with planningId ((class plr.domain.Etat$HibernateProxy$EZnO4cSz,11)) has no known workingObject (null).
Maybe the workingObject was never added because the planning solution doesn't have a @ProblemFactCollectionProperty annotation on a member with instances of the externalObject's class (class plr.domain.Etat$HibernateProxy$EZnO4cSz).

我终于发现升级到v7.17.0.Final时不会出现异常。

自v7.18.0起完成了哪些工作,最终使代码失败了?

如何解决?

编辑: 有关更多信息,请参见相对类

package org.optaplanner.plr.domain;

import javax.persistence.Column;
import javax.persistence.Entity;

import org.optaplanner.core.api.domain.lookup.PlanningId;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Entity
public class Etat extends DbObject {

    @Column
    private String libelle;

    @Column
    private int ordre;

    @Override
    @PlanningId
    public Integer getId() {
        return super.getId();
    }
}

及其超类

package org.optaplanner.plr.domain;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import lombok.Data;
import lombok.EqualsAndHashCode;

@MappedSuperclass
@Data
@EqualsAndHashCode
public abstract class DbObject {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
}

最后,是有史以来最简单的配置:)

<?xml version="1.0" encoding="UTF-8"?>
<solver>
    <!-- To solve faster by saturating multiple CPU cores -->
    <moveThreadCount>4</moveThreadCount>
    <solutionClass>org.optaplanner.plr.domain.PlannifSolution</solutionClass>
    <entityClass>org.optaplanner.plr.domain.Plannif</entityClass>
    <scoreDirectorFactory>
        <scoreDrl>org/optaplanner/plr/solver/score.drl</scoreDrl>
        <initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
    </scoreDirectorFactory>
    <termination>
        <secondsSpentLimit>1200</secondsSpentLimit>
        <unimprovedSecondsSpentLimit>300</unimprovedSecondsSpentLimit>
    </termination>
</solver>

整个踪迹是

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:782)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:763)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
    at org.optaplanner.plr.Application.main(Application.java:64)
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (2) has thrown an exception. Relayed here in the parent thread.
    at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:142)
    at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:187)
    at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:157)
    at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:70)
    at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:88)
    at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:191)
    at org.optaplanner.plr.Application$1.run(Application.java:222)
    at org.optaplanner.plr.Application$1$$FastClassBySpringCGLIB$$7557a0d1.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at org.optaplanner.plr.Application$1$$EnhancerBySpringCGLIB$$c098b4dc.run(<generated>)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:779)
    ... 5 common frames omitted
Caused by: java.lang.IllegalStateException: The externalObject (Etat(super=DbObject(id=11), libelle=RCD, ordre=60)) with planningId ((class org.optaplanner.plr.domain.Etat$HibernateProxy$YghGFDSA,11)) has no known workingObject (null).
Maybe the workingObject was never added because the planning solution doesn't have a @ProblemFactCollectionProperty annotation on a member with instances of the externalObject's class (class org.optaplanner.plr.domain.Etat$HibernateProxy$YghGFDSA).
    at org.optaplanner.core.impl.domain.lookup.PlanningIdLookUpStrategy.lookUpWorkingObject(PlanningIdLookUpStrategy.java:66)
    at org.optaplanner.core.impl.domain.lookup.LookUpManager.lookUpWorkingObject(LookUpManager.java:75)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.lookUpWorkingObject(AbstractScoreDirector.java:509)
    at org.optaplanner.core.impl.heuristic.selector.move.generic.ChangeMove.rebase(ChangeMove.java:85)
    at org.optaplanner.core.impl.heuristic.selector.move.generic.ChangeMove.rebase(ChangeMove.java:33)
    at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:139)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

2 个答案:

答案 0 :(得分:1)

我的理论:

您的代码已经存在错误,但是在7.11中,OptaPlanner并未检测到该错误,并且没有快速失败。从7.18开始,它确实会检测并快速失败,以帮助您 ...

据我所知,没有使用堆栈跟踪,ScoreDirector.lookUpWorkingObject()之类的方法很快就会失败,可能是在给addProblemFactChange()的回调中或在多线程求解中。无论如何,它都无法根据该实体的planningId查找工作实体。

请注意,错误消息是如何表明planningId(通常是LongStringUUID)是类plr.domain.Etat$HibernateProxy$EZnO4cSz的实例。这会在您的问题中证明您的域模型是正确的,它说这是一个整数。在引发消息的地方放置一个断点,然后对此进行验证。

潜在原因:  -一般在附加的JPA对象中混合-我会怀疑  -混合附加的JPA对象,并在没有JPA @Id注释的方法上使用OptaPlanner的@PlanningId注释,从而使JPA代理该方法。

无论哪种方式,在OptaPlanner中使用JPA对象之前先分离它们都将对其进行修复。请确认是否可以解决此问题,所以我可以在错误消息中添加“也许分离您的JPA对象”。

答案 1 :(得分:1)

感谢Geoffrey answeryurloc的评论,我终于找到了问题所在。

首先,Etat个对象通过与另一个对象的联接而到达。将ManyToOne的获取类型更改为Eager而不是Lazy,这表明我遇到了相同的异常,但是对象是Etat,而不是它们的Hibernate代理。

因此,这意味着Optaplanner无法识别这些对象。确实,我为Etat使用了每个计划变量的特定范围,但从未在问题事实中加载所有这些变量。

最后,它与分离对象还是附加对象无关,并且可以将联接提取类型放回Lazy值。