Reputation: 164
When using toList() ConstraintCollector in optaplanner 8.1 like:
factory.from(Lesson.class)
.groupBy(Lesson::getCourse, ConstraintCollectors.toList()).penalize(...);
I run into:
Exception executing consequence for rule "foo" in model: java.lang.ClassCastException: class model.Lesson cannot be cast to class java.util.List (model.Lesson is in unnamed module of loader 'app'; java.util.List is in module java.base of loader 'bootstrap')
at org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
Question: Is this a optaplanner bug, or is my code wrong?
The most simple complete reproducer I find is:
@PlanningSolution
public class OptaplannerIssue2 implements ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory factory) {
return new Constraint[] {factory.from(IssueEntity.class)
.groupBy(IssueEntity::getValue, ConstraintCollectors.toList())
.penalize("x", HardSoftScore.ofHard(1), (entity, enityList) -> 2)};
}
@PlanningScore
private HardSoftScore score = HardSoftScore.ZERO;
@PlanningEntityCollectionProperty
private final List<IssueEntity> entities = new ArrayList<IssueEntity>();
public List<IssueEntity> getEntities() {
return entities;
}
@ValueRangeProvider(id = "valueRange")
public CountableValueRange<Integer> getValueRange() {
return ValueRangeFactory.createIntValueRange(0, 4);
}
public static void main() {
// create Entity
OptaplannerIssue2 issue = new OptaplannerIssue2();
IssueEntity e1 = new IssueEntity();
issue.entities.add(e1);
// solve
SolverFactory<OptaplannerIssue2> solverFactory = SolverFactory.create(new SolverConfig()
.withEnvironmentMode(EnvironmentMode.FULL_ASSERT).withSolutionClass(OptaplannerIssue2.class)
.withEntityClasses(IssueEntity.class)
.withScoreDirectorFactory(
new ScoreDirectorFactoryConfig().withConstraintProviderClass(OptaplannerIssue2.class))
.withTerminationConfig(new TerminationConfig().withSecondsSpentLimit(5L)).withPhases(
new ConstructionHeuristicPhaseConfig()
.withConstructionHeuristicType(ConstructionHeuristicType.FIRST_FIT),
new LocalSearchPhaseConfig().withLocalSearchType(LocalSearchType.LATE_ACCEPTANCE)));
Solver<OptaplannerIssue2> solver = solverFactory.buildSolver();
solver.solve(issue);
}
}
With the following entity-class:
@PlanningEntity
public class IssueEntity {
@PlanningVariable(valueRangeProviderRefs = {"valueRange"})
Integer value;
public Integer getValue() {
return value;
}
}
In the related thread: Optaplanner GroupBy with toList not working as expected the questioner didn't provide all information to commentators trying to help and when I provided reproducer there I got deleted, so I had to ask new question.
Upvotes: 1
Views: 215
Reputation: 5682
The behavior you describe is a bug in OptaPlanner, which we have now fixed. Please upgrade to the next release of OptaPlanner, which at the time of writing this answer will be OptaPlanner 8.2.0.
For details, see PLANNER-2305.
Upvotes: 1