由于 groupBy 操作,OptaPlanner 中的 ClassCastException
ClassCastException in OptaPlanner due to a groupBy operation
我正在创建一个学校时间表生成器,但我的一个约束出现异常,该约束检查所有学生每天都有午休时间。
我正在使用约束流 Java API。我的约束编译(显然)并且看起来像这样:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled) // [Lecture]...
.groupBy(l -> l, l -> l.getCourseRound().getStudents()) // [Lecture, Set<Student>]...
.flattenLast(students -> students) // [Lecture, Student]...
.groupBy((l, s) -> s, // [Student, Map<Day, Set<Lecture>>]...
ConstraintCollectors.toMap(
(l, s) -> l.getStartTimeslot().getDay(),
(l, s) -> l))
//.flattenLast(Map::values) // [Student, Set<Lecture>]...
//.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
为了调试暂时把flattenLast
和filter
注释掉了,问题还是重现。如果我注释掉最后一个 groupBy
,问题似乎不会重现。
出于某种原因,框架试图将 Student
(准确地说是 ImmutableStudent
)转换为 Object[]
。
框架中抛出的行在 ArrayElementReader
中,看起来像这样:
public Object getValue(InternalWorkingMemory workingMemory,
Object object) {
Object[] array = (Object[]) this.arrayReadAccessor.getValue( workingMemory,
object );
return array[this.index];
}
完整的异常如下所示:
java.util.concurrent.ExecutionException: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at java.desktop/javax.swing.SwingWorker.get(SwingWorker.java:613)
at vngschedules.ui.automation.AutomationPanel.done(AutomationPanel.java:44)
at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:750)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:847)
at java.desktop/sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:857)
at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:317)
at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:249)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:147)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:189)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:160)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:95)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:192)
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:29)
at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:10)
at java.desktop/javax.swing.SwingWorker.call(SwingWorker.java:304)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:343)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:162)
at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:279)
at org.drools.modelcompiler.KiePackagesBuilder.lambda$getBindingFunctionde2761(KiePackagesBuilder.java:794)
at org.drools.modelcompiler.constraints.LambdaReadAccessor.getValue(LambdaReadAccessor.java:43)
at org.drools.core.rule.Declaration.getValue(Declaration.java:257)
at org.optaplanner.core.impl.score.stream.drools.common.AbstractAccumulator.extractValue(AbstractAccumulator.java:42)
Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
at org.optaplanner.core.impl.score.stream.drools.common.BiAccumulator.accumulate(BiAccumulator.java:55)
at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:96)
at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:121)
at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:114)
at org.drools.core.phreak.PhreakAccumulateNode.addMatch(PhreakAccumulateNode.java:736)
at org.drools.core.phreak.PhreakAccumulateNode.doRightInserts(PhreakAccumulateNode.java:253)
at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:99)
at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:586)
at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:555)
at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(RuleNetworkEvaluator.java:382)
at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:342)
at org.drools.core.phreak.RuleNetworkEvaluator.evalStackEntry(RuleNetworkEvaluator.java:240)
at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:183)
at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:136)
at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:235)
at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:91)
at org.drools.core.concurrent.AbstractRuleEvaluator.internalEvaluateAndFire(AbstractRuleEvaluator.java:33)
at org.drools.core.concurrent.SequentialRuleEvaluator.evaluateAndFire(SequentialRuleEvaluator.java:43)
at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:869)
at org.drools.core.common.DefaultAgenda.internalFireAllRules(DefaultAgenda.java:816)
at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:808)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1343)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1334)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1326)
at org.optaplanner.core.impl.score.director.stream.DroolsConstraintStreamScoreDirector.calculateScore(DroolsConstraintStreamScoreDirector.java:90)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:220)
at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:147)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
... 3 more
我已经注释掉了我程序中的所有其他约束流。
问题
- 这看起来像是我的代码中的错误,还是 OptaPlanner 的问题?
- 如果它在我的代码中,是否有任何调试技巧?我怀疑我的约束被编译成 Drools-something。有没有办法跳过这个编译,让异常可以追溯到我的代码? (截至目前,异常中没有任何行可以追溯到我的代码。)
很高兴在需要时提供更多类型,但 RecurringLecture
确实非常简单,Student
是一个编译成 ImmutableStudent
.
的不可变接口
我正在使用 OptaPlanner 8.12.0.Final 和 Java 11.
更新
我尝试重写约束流如下:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled) // [Lecture]...
.groupBy(l -> l, l -> l.getCourseRound().getStudents()) // [Lecture, Set<Student>]...
.flattenLast(students -> students) // [Lecture, Student]...
.groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
ConstraintCollectors.toSet((l, s) -> l))
.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
这避免了 toMap
收集器。然而,我仍然 运行 遇到完全相同的问题。
一般来说,如果您的约束编译成功并且代码在运行时仍然抛出 ClassCastException
,您应该认为该错误出在 OptaPlanner 方面。除非你愿意查看 Drools 可执行模型,否则那里没有任何东西可供你调试。
我建议将约束重构为如下所示:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled)
.join(Student.class,
Joiners.filtering((l, s) -> l.getCourseRound().getStudents().contains(s)))
.groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
ConstraintCollectors.toSet((l, s) -> l))
.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
我希望它能表现得更好,也可能会消除异常。无论如何,异常仍然是一个问题,如果您提供简化的可执行复制器,我将进一步调查它。
我正在创建一个学校时间表生成器,但我的一个约束出现异常,该约束检查所有学生每天都有午休时间。
我正在使用约束流 Java API。我的约束编译(显然)并且看起来像这样:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled) // [Lecture]...
.groupBy(l -> l, l -> l.getCourseRound().getStudents()) // [Lecture, Set<Student>]...
.flattenLast(students -> students) // [Lecture, Student]...
.groupBy((l, s) -> s, // [Student, Map<Day, Set<Lecture>>]...
ConstraintCollectors.toMap(
(l, s) -> l.getStartTimeslot().getDay(),
(l, s) -> l))
//.flattenLast(Map::values) // [Student, Set<Lecture>]...
//.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
为了调试暂时把flattenLast
和filter
注释掉了,问题还是重现。如果我注释掉最后一个 groupBy
,问题似乎不会重现。
出于某种原因,框架试图将 Student
(准确地说是 ImmutableStudent
)转换为 Object[]
。
框架中抛出的行在 ArrayElementReader
中,看起来像这样:
public Object getValue(InternalWorkingMemory workingMemory,
Object object) {
Object[] array = (Object[]) this.arrayReadAccessor.getValue( workingMemory,
object );
return array[this.index];
}
完整的异常如下所示:
java.util.concurrent.ExecutionException: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at java.desktop/javax.swing.SwingWorker.get(SwingWorker.java:613)
at vngschedules.ui.automation.AutomationPanel.done(AutomationPanel.java:44)
at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:750)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:847)
at java.desktop/sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:857)
at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:317)
at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:249)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:147)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:189)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:160)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:95)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:192)
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (1) has thrown an exception. Relayed here in the parent thread.
at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:29)
at vngschedules.ui.automation.SolverSwingWorker.doInBackground(SolverSwingWorker.java:10)
at java.desktop/javax.swing.SwingWorker.call(SwingWorker.java:304)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:343)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:162)
at org.drools.core.base.extractors.ArrayElementReader.getValue(ArrayElementReader.java:279)
at org.drools.modelcompiler.KiePackagesBuilder.lambda$getBindingFunctionde2761(KiePackagesBuilder.java:794)
at org.drools.modelcompiler.constraints.LambdaReadAccessor.getValue(LambdaReadAccessor.java:43)
at org.drools.core.rule.Declaration.getValue(Declaration.java:257)
at org.optaplanner.core.impl.score.stream.drools.common.AbstractAccumulator.extractValue(AbstractAccumulator.java:42)
Caused by: java.lang.ClassCastException: class vngschedules.schedule.ImmutableStudent cannot be cast to class [Ljava.lang.Object; (vngschedules.schedule.ImmutableStudent is in unnamed module of loader 'app'; [Ljava.lang.Object; is in module java.base of loader 'bootstrap')
at org.optaplanner.core.impl.score.stream.drools.common.BiAccumulator.accumulate(BiAccumulator.java:55)
at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:96)
at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:121)
at org.drools.modelcompiler.constraints.LambdaGroupByAccumulate.accumulate(LambdaGroupByAccumulate.java:114)
at org.drools.core.phreak.PhreakAccumulateNode.addMatch(PhreakAccumulateNode.java:736)
at org.drools.core.phreak.PhreakAccumulateNode.doRightInserts(PhreakAccumulateNode.java:253)
at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:99)
at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:586)
at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:555)
at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(RuleNetworkEvaluator.java:382)
at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:342)
at org.drools.core.phreak.RuleNetworkEvaluator.evalStackEntry(RuleNetworkEvaluator.java:240)
at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:183)
at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:136)
at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:235)
at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:91)
at org.drools.core.concurrent.AbstractRuleEvaluator.internalEvaluateAndFire(AbstractRuleEvaluator.java:33)
at org.drools.core.concurrent.SequentialRuleEvaluator.evaluateAndFire(SequentialRuleEvaluator.java:43)
at org.drools.core.common.DefaultAgenda.fireLoop(DefaultAgenda.java:869)
at org.drools.core.common.DefaultAgenda.internalFireAllRules(DefaultAgenda.java:816)
at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:808)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(StatefulKnowledgeSessionImpl.java:1343)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1334)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1326)
at org.optaplanner.core.impl.score.director.stream.DroolsConstraintStreamScoreDirector.calculateScore(DroolsConstraintStreamScoreDirector.java:90)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:220)
at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:147)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
... 3 more
我已经注释掉了我程序中的所有其他约束流。
问题
- 这看起来像是我的代码中的错误,还是 OptaPlanner 的问题?
- 如果它在我的代码中,是否有任何调试技巧?我怀疑我的约束被编译成 Drools-something。有没有办法跳过这个编译,让异常可以追溯到我的代码? (截至目前,异常中没有任何行可以追溯到我的代码。)
很高兴在需要时提供更多类型,但 RecurringLecture
确实非常简单,Student
是一个编译成 ImmutableStudent
.
我正在使用 OptaPlanner 8.12.0.Final 和 Java 11.
更新
我尝试重写约束流如下:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled) // [Lecture]...
.groupBy(l -> l, l -> l.getCourseRound().getStudents()) // [Lecture, Set<Student>]...
.flattenLast(students -> students) // [Lecture, Student]...
.groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
ConstraintCollectors.toSet((l, s) -> l))
.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
这避免了 toMap
收集器。然而,我仍然 运行 遇到完全相同的问题。
一般来说,如果您的约束编译成功并且代码在运行时仍然抛出 ClassCastException
,您应该认为该错误出在 OptaPlanner 方面。除非你愿意查看 Drools 可执行模型,否则那里没有任何东西可供你调试。
我建议将约束重构为如下所示:
public Constraint studentsShouldHaveLunchEveryDay(ConstraintFactory cf) {
return cf.from(RecurringLecture.class)
.filter(RecurringLecture::isScheduled)
.join(Student.class,
Joiners.filtering((l, s) -> l.getCourseRound().getStudents().contains(s)))
.groupBy((l, s) -> ImmutableStudentAndDay.of(s, l.getStartTimeslot().getDay()),
ConstraintCollectors.toSet((l, s) -> l))
.filter((student, dailyLectures) -> !LunchBreakAnalyzer.hasLunchBreak(dailyLectures))
.penalize(StudentLunchProblem.class.getName(), HardSoftScore.ONE_HARD);
}
我希望它能表现得更好,也可能会消除异常。无论如何,异常仍然是一个问题,如果您提供简化的可执行复制器,我将进一步调查它。