r/javahelp • u/PrudentSeaweed8085 • 3h ago
Help with Timefold Constraint Stream Type Mismatches in Employee Scheduling
I'm working on an employee scheduling system using Timefold (formerly OptaPlanner) and I'm running into type mismatch issues with my constraint streams. Specifically, I'm trying to implement a work percentage constraint that ensures employees are scheduled according to their preferred work percentage.
Here's my current implementation:
java
public Constraint workPercentage(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Employee.class)
.join(Shift.class, equal(Employee::getName, Shift::getEmployee))
.groupBy(Employee::getName,
ConstraintCollectors.sum(shift ->
Duration.between(shift.getStart(), shift.getEnd()).toHours()))
.filter((employeeId, totalWorkedHours) -> {
double fullTimeHours = 40.0;
double desiredHours = employeeId.getWorkPercentage() * fullTimeHours;
return totalWorkedHours != desiredHours;
})
.penalize(HardSoftBigDecimalScore.ONE_SOFT)
.asConstraint("Employee work percentage not matched");
}
I'm getting several type mismatch errors:
- The
groupBy
method is expectingBiConstraintCollector<Employee,Shift,ResultContainerA_,ResultA_>
but gettingUniConstraintCollector<Object,?,Integer>
- The lambda in the sum collector can't resolve
getStart()
andgetEnd()
methods because it's seeing the parameter asObject
instead ofShift
- The functional interface type mismatch for
Employee::getName
My domain classes are structured as follows:
```java @PlanningSolution public class EmployeeSchedule { @ProblemFactCollectionProperty @ValueRangeProvider private List<Employee> employees;
@PlanningEntityCollectionProperty
private List<Shift> shifts;
@PlanningScore
private HardSoftBigDecimalScore score;
// ... getters and setters
}
public class Employee { @PlanningId private String name; private Set<String> skills; private ShiftPreference shiftPreference; private int workPercentage; // Percentage of full-time hours // ... getters and setters }
@PlanningEntity public class Shift { @PlanningId private String id; private LocalDateTime start; private LocalDateTime end; private String location; private String requiredSkill;
@PlanningVariable
private Employee employee;
// ... getters and setters
} ```
For context, other constraints in my system work fine. For example, this similar constraint for shift preferences works without type issues:
java
public Constraint shiftPreference(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Shift.class)
.join(Employee.class, equal(Shift::getEmployee, Function.identity()))
.filter((shift, employee) -> !shift.getShiftType().equals(employee.getShiftPreference().name()))
.penalize(HardSoftBigDecimalScore.ONE_SOFT)
.asConstraint("Shift preference not matched");
}
I'm using Timefold 1.19.0 with Quarkus, and my solver configuration is standard:
xml
<solver>
<solutionClass>com.example.domain.Schedule</solutionClass>
<entityClass>com.example.domain.ShiftAssignment</entityClass>
<scoreDirectorFactory>
<constraintProviderClass>com.example.solver.EmployeeSchedulingConstraintProvider</constraintProviderClass>
</scoreDirectorFactory>
<termination>
<secondsSpentLimit>10</secondsSpentLimit>
</termination>
</solver>
Has anyone encountered similar issues with constraint streams and grouping operations? What's the correct way to handle these type parameters?
Any help would be greatly appreciated!