OptaPlanner 域访问类型 Gizmo

OptaPlanner domainAccessType Gizmo

我正在尝试在我的求解器配置中使用 <domainAccessType>GIZMO</domainAccessType>

它似乎可以快速访问我的大部分变量,但它会为我的 @PlanningSolution:

中的变量抛出异常
17:30:17.863 [main        ] TRACE     Model annotations parsed for solution VehicleRoutingSolution:
17:30:17.866 [main        ] TRACE         Entity Standstill:
17:30:17.866 [main        ] TRACE             Shadow variable nextVisit (Fast access with generated bytecode)
17:30:17.866 [main        ] TRACE         Entity Visit:
17:30:17.866 [main        ] TRACE             Genuine variable previousStandstill (Fast access with generated bytecode)
17:30:17.866 [main        ] TRACE             Shadow variable arrivalTime (Fast access with generated bytecode)
17:30:17.866 [main        ] TRACE             Shadow variable subShift (Fast access with generated bytecode)
Exception in thread "main" java.lang.IllegalStateException: Member (solverStatus) of class (org.acme.domain.VehicleRoutingSolution) is not public and domainAccessType is GIZMO.
Maybe put the annotations onto the public getter of the field.
Maybe use domainAccessType REFLECTION instead of GIZMO.
    at org.optaplanner.core.impl.domain.common.accessor.gizmo.GizmoMemberDescriptor.<init>(GizmoMemberDescriptor.java:79)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionOrEntityDescriptor.getFieldsToSolutionFieldToMemberDescriptorMap(GizmoSolutionOrEntityDescriptor.java:63)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionOrEntityDescriptor.<init>(GizmoSolutionOrEntityDescriptor.java:39)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionClonerImplementor.lambda$createCloneSolutionRun(GizmoSolutionClonerImplementor.java:294)
    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1220)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionClonerImplementor.createCloneSolutionRun(GizmoSolutionClonerImplementor.java:293)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionClonerImplementor.defineClonerFor(GizmoSolutionClonerImplementor.java:157)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionClonerImplementor.createClonerFor(GizmoSolutionClonerImplementor.java:200)
    at org.optaplanner.core.impl.domain.solution.cloner.gizmo.GizmoSolutionClonerFactory.build(GizmoSolutionClonerFactory.java:31)
    at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.initSolutionCloner(SolutionDescriptor.java:601)
    at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.afterAnnotationsProcessed(SolutionDescriptor.java:545)
    at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.buildSolutionDescriptor(SolutionDescriptor.java:126)
    at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildSolutionDescriptor(DefaultSolverFactory.java:160)
    at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildScoreDirectorFactory(DefaultSolverFactory.java:133)
    at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildSolver(DefaultSolverFactory.java:87)
    at org.optaplanner.core.impl.solver.DefaultSolverManager.validateSolverFactory(DefaultSolverManager.java:69)
    at org.optaplanner.core.impl.solver.DefaultSolverManager.<init>(DefaultSolverManager.java:58)
    at org.optaplanner.core.api.solver.SolverManager.create(SolverManager.java:111)
    at org.optaplanner.core.api.solver.SolverManager.create(SolverManager.java:84)

这是我正在使用的规划解决方案:

@PlanningSolution
class VehicleRoutingSolution {

    @PlanningEntityCollectionProperty
    @ValueRangeProvider(id = "visitRange")
    lateinit var visitList: List<Visit>

    @PlanningEntityCollectionProperty
    @ValueRangeProvider(id = "subShiftRange")
    lateinit var subShiftList: List<SubShift>


    private var solverStatus: SolverStatus? = null
    fun getSolverStatus(): SolverStatus? {
        return solverStatus
    }
    fun setSolverStatus(solverStatus: SolverStatus?) {
        this.solverStatus = solverStatus
    }

    private var score: SimpleLongScore? = null
    @PlanningScore
    fun getScore(): SimpleLongScore? {
        return score
    }
    fun setScore(score: SimpleLongScore?) {
        this.score = score
    }

    // No-arg constructor required for OptaPlanner
    constructor() {}

    constructor(subShiftList: List<SubShift>, visitList: List<Visit>) {
        this.subShiftList = subShiftList
        this.visitList = visitList
    }

}

solverStatus 甚至没有注释,所以我不明白为什么它会抱怨这个。

奇怪的是,如果我将 score 变量部分放在 solverStatus 部分之上,它会抱怨 score 不是 public,而 getter显然是。

知道这里发生了什么吗?

无法在 Quarkus 中重现。看到 https://github.com/kiegroup/optaplanner-quickstarts/tree/stable/technology/kotlin-quarkus for an example of using OptaPlanner with Kotlin in Quarkus. I tested changing the the fields of TimeTable 到 private,它按预期工作。

在 Quarkus 之外,这种行为是预期的。当使用域访问类型 GIZMO 时,将为域生成成员访问器和自定义解决方案克隆器。自定义解决方案克隆器要求所有字段为 public; public getters/setters 未被使用,因为它们不能保证简单(它们可以进行抛出异常的验证检查,或修改其他字段)。