OptaPlanner使用@PlanningListVariable时多规划变量启动报错
OptaPlanner多规划变量场景启动报错修复
问题背景
使用OptaPlanner实现时间表自动生成功能,需求为单个活动(规划实体)分配多名协作人员(规划变量),判断支持List类型作为规划变量即可满足需求,找到@PlanningListVariable注解但未掌握具体使用方法,无公开参考案例,编写的规划实体代码如下:
@PlanningEntity @Entity @Table(name = "activity") public class Activity implements Serializable { private static final long serialVersionUID = 1L; @PlanningId @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "activity_label") private String activityLabel; // @PlanningVariable(valueRangeProviderRefs = "locationRange") @PlanningListVariable(valueRangeProviderRefs = "locationRange") @JsonIgnoreProperties(value = { "resource", "typeOfLocation" }, allowSetters = true) @ManyToMany private List<Location> location; @PlanningListVariable(valueRangeProviderRefs = "collaboratorRange") @ManyToMany @JsonIgnoreProperties(value = { "resource", "typeOfCollaborator" }, allowSetters = true) private List<Collaborator> collaborator; @PlanningVariable(valueRangeProviderRefs = "equipmentRange") @ManyToOne @JsonIgnoreProperties(value = { "resource", "typeOfEquipment" }, allowSetters = true) private Equipment equipment; ... }
报错现象
代码编写完成后启动应用抛出异常,核心错误日志如下:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.optaplanner.core.api.solver.SolverManager]: Factory method 'solverManager' threw exception; nested exception is java.lang.IllegalArgumentException: The config (ValueSelectorConfig(null)) has no configured variableName for entityClass (class com.planning.sp.domain.Activity) and because there are multiple variableNames ([collaborator, equipment, location, period]), it cannot be deduced automatically.
异常核心逻辑:
ValueSelectorConfig未针对实体类com.planning.sp.domain.Activity配置variableName,该实体存在collaborator、equipment、location、period多个规划变量,框架无法自动推导对应变量名称,最终导致SolverManager实例化失败、应用启动报错。
根因与修复方案
- 根因1:同个规划实体下同时混用单值规划变量(
@PlanningVariable修饰,如equipment、period)和列表规划变量(@PlanningListVariable修饰,如location、collaborator)时,OptaPlanner默认的自动求解配置无法自动推断每个值选择器对应的变量,必须显式手动配置,不能依赖框架自动推导。 - 根因2:
@PlanningListVariable是OptaPlanner为多值分配场景设计的专用注解,默认的移动生成器仅适配单值规划变量,列表变量需要搭配专用的列表移动生成器,未配置时也会触发配置推导失败的问题。
具体修复操作:
- 版本校验:将OptaPlanner升级至8.20及以上稳定版本,低于该版本的
@PlanningListVariable为实验性功能,存在大量Spring Boot自动配置兼容问题。 - 实体初始化:给所有
@PlanningListVariable修饰的字段初始化为空的可变集合(如new ArrayList<>()),不能为null,也不要提前预置业务初始值,避免求解器初始化阶段报错。 - 显式配置求解规则:不要依赖默认自动配置,在求解器配置文件(Spring Boot项目可放在
solverConfig.xml,或通过配置类声明)中为每个规划变量显式指定值选择器,列表变量必须使用专用的列表移动选择器,参考配置如下:
<solver> <!-- 域访问、终止条件等基础配置保持原有逻辑即可 --> <constructionHeuristic> <!-- 逐个声明所有单值、列表变量的放置规则 --> <queuedValuePlacer> <valueSelector variableName="period"/> </queuedValuePlacer> <queuedValuePlacer> <valueSelector variableName="equipment"/> </queuedValuePlacer> <queuedValuePlacer> <valueSelector variableName="location"/> </queuedValuePlacer> <queuedValuePlacer> <valueSelector variableName="collaborator"/> </queuedValuePlacer> </constructionHeuristic> <localSearch> <unionMoveSelector> <!-- 单值变量用普通changeMoveSelector --> <changeMoveSelector> <valueSelector variableName="period"/> </changeMoveSelector> <changeMoveSelector> <valueSelector variableName="equipment"/> </changeMoveSelector> <!-- 列表变量必须使用专用的listChangeMoveSelector、listSwapMoveSelector --> <listChangeMoveSelector> <valueSelector variableName="location"/> </listChangeMoveSelector> <listChangeMoveSelector> <valueSelector variableName="collaborator"/> </listChangeMoveSelector> <listSwapMoveSelector> <valueSelector variableName="location"/> </listSwapMoveSelector> <listSwapMoveSelector> <valueSelector variableName="collaborator"/> </listSwapMoveSelector> </unionMoveSelector> </localSearch> </solver>
- 配置加载:如果是Spring Boot项目,在
application.yml中指定求解器配置路径,确保自定义配置被正确加载:
optaplanner: solver: solver-config-xml: classpath:solverConfig.xml
内容的提问来源于stack exchange,提问作者Harold-debug
相关产品推荐
相关产品推荐

