Я работаю над проектом балансировки облаков optaplanner-spring-boot-starter и пытаюсь назначать смены сотрудникам на основе их уровня квалификации. Однако, когда я передаю объект JSON своему контроллеру реестра, я получаю сообщение об ошибке:
java .lang.IllegalArgumentException: SolutionClass (класс com.redhat.optaplannersbs.domain.Roster) entityCollectionProperty (свойство bean-компонента shiftList для класса com.redhat.optaplannersbs.domain.Roster) никогда не должно возвращать значение null.
Я не понимаю, в чем проблема, поскольку я делаю то же самое, что и проблема балансировки облаков и это работает и решает нормально.
Вот мой код для класса сотрудников:
public class Employee {
private int eid;
private String name;
private int skillLevel;
public Employee(){
}
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// constraint getters and setters
public int getSkillLevel() {
return skillLevel;
}
public void setSkillLevel(int skillLevel) {
this.skillLevel = skillLevel;
}
}
Вот мой код для сменного класса:
@PlanningEntity
public class Shift {
private int sid;
private LocalTime startTime;
private LocalTime endTime;
private int requiredSkillLevel;
@PlanningVariable(valueRangeProviderRefs = "employee")
private Employee employee;
public Shift(){
}
public Shift(Long deptId, Long spotId, LocalTime startTime,
LocalTime endTime, Long employeeId){
this.startTime = startTime;
this.endTime = endTime;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public LocalTime getStartTime() {
return startTime;
}
public void setStartTime(LocalTime startTime) {
this.startTime = startTime;
}
public LocalTime getEndTime() {
return endTime;
}
public void setEndTime(LocalTime endTime) {
this.endTime = endTime;
}
// planning variable getter and setter
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public int getRequiredSkillLevel() {
return requiredSkillLevel;
}
public void setRequiredSkillLevel(int requiredSkillLevel) {
this.requiredSkillLevel = requiredSkillLevel;
}
}
Вот мой класс Ростера:
@PlanningSolution
public class Roster {
private List<Employee> employeeList;
private List<Shift> shiftList;
private HardSoftScore score;
public Roster(List<Employee> employeeList, List<Shift> shiftList) {
this.employeeList = employeeList;
this.shiftList = shiftList;
}
@ProblemFactCollectionProperty
@ValueRangeProvider(id="employee")
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
@PlanningEntityCollectionProperty
public List<Shift> getShiftList() {
return shiftList;
}
public void setShiftList(List<Shift> shiftList) {
this.shiftList = shiftList;
}
@PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
}
Вот мой поставщик ограничений:
public class ConstraintProvider implements org.optaplanner.core.api.score.stream.ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[]{
requiredSkillLevelOfEmployeesForShifts(constraintFactory)
};
}
private Constraint requiredSkillLevelOfEmployeesForShifts(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, sum(Shift::getRequiredSkillLevel))
.filter((employee, requiredSkillLevel) -> requiredSkillLevel > employee.getSkillLevel())
.penalize("requiredSkillLevelForShifts",
HardSoftScore.ONE_HARD,
(employee, requiredSkillLevel) -> requiredSkillLevel - employee.getSkillLevel());
}
}
Вот мой контроллер:
@RestController
@RequestMapping("/roster")
public class RosterController {
@Autowired
private SolverManager<Roster, UUID> solverManager;
@PostMapping("/solve")
public Roster solve(@RequestBody Roster problem) {
UUID problemId = UUID.randomUUID();
// Submit the problem to start solving
SolverJob<Roster, UUID> solverJob = solverManager.solve(problemId, problem);
Roster solution;
try {
// Wait until the solving ends
solution = solverJob.getFinalBestSolution();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Solving failed.", e);
}
return solution;
}
}
Данные JSON, которые я передаю пост-запрос выглядит следующим образом:
{
"shifts":[
{
"sid":0,
"startTime":"09:00",
"endTime":"18:00",
"requiredSkillLevel": 12
},
{
"sid":1,
"startTime":"12:00",
"endTime":"20:00",
"requiredSkillLevel": 10
},
{
"sid":2,
"startTime":"18:00",
"endTime":"00:00",
"requiredSkillLevel": 10
},
{
"sid": 3,
"startTime":"09:00",
"endTime":"18:00",
"requiredSkillLevel": 12
},
{
"sid":4,
"startTime":"12:00",
"endTime":"20:00",
"requiredSkillLevel": 10
},
{
"sid":5,
"startTime":"18:00",
"endTime":"00:00",
"requiredSkillLevel":10
},
{
"sid":6,
"startTime":"09:00",
"endTime":"18:00",
"requiredSkillLevel": 12
},
{
"sid":7,
"startTime":"12:00",
"endTime":"20:00",
"requiredSkillLevel": 10
},
{
"sid":8,
"startTime":"18:00",
"endTime":"00:00",
"requiredSkillLevel":10
},
{
"sid":9,
"startTime":"09:00",
"endTime":"18:00",
"requiredSkillLevel": 12
},
{
"sid":10,
"startTime":"12:00",
"endTime":"20:00",
"requiredSkillLevel": 10
},
{
"sid":11,
"startTime":"18:00",
"endTime":"00:00",
"requiredSkillLevel":10
},
{
"sid":12,
"startTime":"09:00",
"endTime":"18:00",
"requiredSkillLevel": 12
},
{
"sid":13,
"startTime":"12:00",
"endTime":"20:00",
"requiredSkillLevel": 10
},
{
"sid":14,
"startTime":"18:00",
"endTime":"00:00",
"requiredSkillLevel":10
}
],
"employees":[
{
"eid":0,
"name":"john",
"skillLevel": 10
},
{
"eid":1,
"name":"elaine",
"skillLevel": 2
},
{
"eid":2,
"name":"kieran",
"skillLevel": 11
},
{
"eid":3,
"name":"maeve",
"skillLevel": 10
},
{
"eid":4,
"name":"steve",
"skillLevel": 9
},
{
"eid":5,
"name":"steve",
"skillLevel": 9
},
{
"eid":6,
"name":"steve",
"skillLevel": 15
},
{
"eid":7,
"name":"amy",
"skillLevel": 11
}
]
}
Я не должен получать эту ошибку, поскольку я делаю еще более простую версию приложения балансировки облака, если кто-то может выяснить, где я иду неправильно, что будет большой хель р