|
1 | 1 | package ai.timefold.solver.core.impl.domain.variable.descriptor; |
2 | 2 |
|
| 3 | +import ai.timefold.solver.core.api.domain.common.SorterFactory; |
3 | 4 | import ai.timefold.solver.core.api.domain.variable.PlanningVariable; |
4 | 5 | import ai.timefold.solver.core.api.domain.variable.PlanningVariableGraphType; |
5 | 6 | import ai.timefold.solver.core.impl.domain.common.accessor.MemberAccessor; |
|
8 | 9 | import ai.timefold.solver.core.impl.heuristic.selector.common.decorator.SelectionFilter; |
9 | 10 | import ai.timefold.solver.core.impl.heuristic.selector.value.decorator.MovableChainedTrailingValueFilter; |
10 | 11 |
|
| 12 | +import java.util.Comparator; |
| 13 | + |
11 | 14 | public final class BasicVariableDescriptor<Solution_> extends GenuineVariableDescriptor<Solution_> { |
12 | 15 |
|
13 | 16 | private SelectionFilter<Solution_, Object> movableChainedTrailingValueFilter; |
@@ -41,8 +44,60 @@ protected void processPropertyAnnotations(DescriptorPolicy descriptorPolicy) { |
41 | 44 | processAllowsUnassigned(planningVariableAnnotation); |
42 | 45 | processChained(planningVariableAnnotation); |
43 | 46 | processValueRangeRefs(descriptorPolicy, planningVariableAnnotation.valueRangeProviderRefs()); |
44 | | - processSorting("strengthComparatorClass", planningVariableAnnotation.strengthComparatorClass(), |
45 | | - "strengthWeightFactoryClass", planningVariableAnnotation.strengthWeightFactoryClass()); |
| 47 | + var sortingProperties = assertSortingProperties(planningVariableAnnotation); |
| 48 | + processSorting(sortingProperties.comparatorPropertyName(), sortingProperties.comparatorClass(), |
| 49 | + sortingProperties.comparatorFactoryPropertyName(), sortingProperties.comparatorFactoryClass()); |
| 50 | + } |
| 51 | + |
| 52 | + private SortingProperties assertSortingProperties(PlanningVariable planningVariableAnnotation) { |
| 53 | + // Comparator property |
| 54 | + var strengthComparatorClass = planningVariableAnnotation.strengthComparatorClass(); |
| 55 | + var comparatorClass = planningVariableAnnotation.comparatorClass(); |
| 56 | + if (strengthComparatorClass != null |
| 57 | + && PlanningVariable.NullComparator.class.isAssignableFrom(strengthComparatorClass)) { |
| 58 | + strengthComparatorClass = null; |
| 59 | + } |
| 60 | + if (comparatorClass != null && PlanningVariable.NullComparator.class.isAssignableFrom(comparatorClass)) { |
| 61 | + comparatorClass = null; |
| 62 | + } |
| 63 | + if (strengthComparatorClass != null && comparatorClass != null) { |
| 64 | + throw new IllegalStateException( |
| 65 | + "The entityClass (%s) property (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted( |
| 66 | + entityDescriptor.getEntityClass(), variableMemberAccessor.getName(), "strengthComparatorClass", |
| 67 | + strengthComparatorClass.getName(), "comparatorClass", comparatorClass.getName())); |
| 68 | + } |
| 69 | + // Comparator factory property |
| 70 | + var strengthWeightFactoryClass = planningVariableAnnotation.strengthWeightFactoryClass(); |
| 71 | + var comparatorFactoryClass = planningVariableAnnotation.comparatorFactoryClass(); |
| 72 | + if (strengthWeightFactoryClass != null |
| 73 | + && PlanningVariable.NullComparatorFactory.class.isAssignableFrom(strengthWeightFactoryClass)) { |
| 74 | + strengthWeightFactoryClass = null; |
| 75 | + } |
| 76 | + if (comparatorFactoryClass != null |
| 77 | + && PlanningVariable.NullComparatorFactory.class.isAssignableFrom(comparatorFactoryClass)) { |
| 78 | + comparatorFactoryClass = null; |
| 79 | + } |
| 80 | + if (strengthWeightFactoryClass != null && comparatorFactoryClass != null) { |
| 81 | + throw new IllegalStateException( |
| 82 | + "The entityClass (%s) property (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted( |
| 83 | + entityDescriptor.getEntityClass(), variableMemberAccessor.getName(), "strengthWeightFactoryClass", |
| 84 | + strengthWeightFactoryClass.getName(), "comparatorFactoryClass", comparatorFactoryClass.getName())); |
| 85 | + } |
| 86 | + // Final properties |
| 87 | + var comparatorPropertyName = "comparatorClass"; |
| 88 | + var comparatorPropertyClass = comparatorClass; |
| 89 | + var factoryPropertyName = "comparatorFactoryClass"; |
| 90 | + var factoryPropertyClass = comparatorFactoryClass; |
| 91 | + if (strengthComparatorClass != null) { |
| 92 | + comparatorPropertyName = "strengthComparatorClass"; |
| 93 | + comparatorPropertyClass = strengthComparatorClass; |
| 94 | + } |
| 95 | + if (strengthWeightFactoryClass != null) { |
| 96 | + factoryPropertyName = "strengthWeightFactoryClass"; |
| 97 | + factoryPropertyClass = strengthWeightFactoryClass; |
| 98 | + } |
| 99 | + return new SortingProperties(comparatorPropertyName, comparatorPropertyClass, factoryPropertyName, |
| 100 | + factoryPropertyClass); |
46 | 101 | } |
47 | 102 |
|
48 | 103 | private void processAllowsUnassigned(PlanningVariable planningVariableAnnotation) { |
@@ -130,4 +185,9 @@ public SelectionFilter<Solution_, Object> getMovableChainedTrailingValueFilter() |
130 | 185 | return movableChainedTrailingValueFilter; |
131 | 186 | } |
132 | 187 |
|
| 188 | + private record SortingProperties(String comparatorPropertyName, Class<? extends Comparator> comparatorClass, |
| 189 | + String comparatorFactoryPropertyName, Class<? extends SorterFactory> comparatorFactoryClass) { |
| 190 | + |
| 191 | + } |
| 192 | + |
133 | 193 | } |
0 commit comments