Optaplanner solutionClass entityCollectionProperty никогда не должен возвращать нулевую ошибку, когда простой JSON объект передается в контроллер - PullRequest
1 голос
/ 16 апреля 2020

Я работаю над проектом балансировки облаков 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
      }
   ]
}

Я не должен получать эту ошибку, поскольку я делаю еще более простую версию приложения балансировки облака, если кто-то может выяснить, где я иду неправильно, что будет большой хель р

1 Ответ

1 голос
/ 16 апреля 2020

Установите точку останова в вашем RosterController непосредственно перед вызовом solverManager.solve(...). Вы увидите, что у вашего Roster экземпляра есть поле shiftList, равное null.

. Проблема в том, что json не выполняет маршалинг ваших входных данных из-за несоответствия имен во входных данных json. Обратите внимание, что по умолчанию Джексон в Spring Boot игнорирует свойства, которые не существуют, вместо того, чтобы выдержать неудачу (решение по дизайну, которое я никогда не понимал). Есть свойство изменить это поведение IIR C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...