Skip to content

Commit bfe62ca

Browse files
committed
refactor: remove deprecated methods from ScoreDirector
1 parent 9c306aa commit bfe62ca

12 files changed

Lines changed: 50 additions & 164 deletions

core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java

Lines changed: 2 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import ai.timefold.solver.core.api.score.Score;
66
import ai.timefold.solver.core.api.solver.change.ProblemChange;
77

8-
import org.jspecify.annotations.NonNull;
8+
import org.jspecify.annotations.NullMarked;
99
import org.jspecify.annotations.Nullable;
1010

1111
/**
@@ -14,6 +14,7 @@
1414
*
1515
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
1616
*/
17+
@NullMarked
1718
public interface ScoreDirector<Solution_> {
1819

1920
/**
@@ -22,7 +23,6 @@ public interface ScoreDirector<Solution_> {
2223
* Because a {@link Score} is best calculated incrementally (by deltas),
2324
* the {@link ScoreDirector} needs to be notified when its {@link PlanningSolution working solution} changes.
2425
*/
25-
@NonNull
2626
Solution_ getWorkingSolution();
2727

2828
void beforeVariableChanged(Object entity, String variableName);
@@ -43,96 +43,6 @@ public interface ScoreDirector<Solution_> {
4343

4444
void triggerVariableListeners();
4545

46-
/**
47-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
48-
* Use {@link ProblemChange} instead.
49-
*/
50-
@Deprecated(forRemoval = true, since = "1.8.0")
51-
default void beforeEntityAdded(Object entity) {
52-
throw new UnsupportedOperationException();
53-
}
54-
55-
/**
56-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
57-
* Use {@link ProblemChange} instead.
58-
*/
59-
@Deprecated(forRemoval = true, since = "1.8.0")
60-
default void afterEntityAdded(Object entity) {
61-
throw new UnsupportedOperationException();
62-
}
63-
64-
/**
65-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
66-
* Use {@link ProblemChange} instead.
67-
*/
68-
@Deprecated(forRemoval = true, since = "1.8.0")
69-
default void beforeEntityRemoved(Object entity) {
70-
throw new UnsupportedOperationException();
71-
}
72-
73-
/**
74-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
75-
* Use {@link ProblemChange} instead.
76-
*/
77-
@Deprecated(forRemoval = true, since = "1.8.0")
78-
default void afterEntityRemoved(Object entity) {
79-
throw new UnsupportedOperationException();
80-
}
81-
82-
/**
83-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
84-
* Use {@link ProblemChange} instead.
85-
*/
86-
@Deprecated(forRemoval = true, since = "1.8.0")
87-
default void beforeProblemFactAdded(Object problemFact) {
88-
throw new UnsupportedOperationException();
89-
}
90-
91-
/**
92-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
93-
* Use {@link ProblemChange} instead.
94-
*/
95-
@Deprecated(forRemoval = true, since = "1.8.0")
96-
default void afterProblemFactAdded(Object problemFact) {
97-
throw new UnsupportedOperationException();
98-
}
99-
100-
/**
101-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
102-
* Use {@link ProblemChange} instead.
103-
*/
104-
@Deprecated(forRemoval = true, since = "1.8.0")
105-
default void beforeProblemPropertyChanged(Object problemFactOrEntity) {
106-
throw new UnsupportedOperationException();
107-
}
108-
109-
/**
110-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
111-
* Use {@link ProblemChange} instead.
112-
*/
113-
@Deprecated(forRemoval = true, since = "1.8.0")
114-
default void afterProblemPropertyChanged(Object problemFactOrEntity) {
115-
throw new UnsupportedOperationException();
116-
}
117-
118-
/**
119-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
120-
* Use {@link ProblemChange} instead.
121-
*/
122-
@Deprecated(forRemoval = true, since = "1.8.0")
123-
default void beforeProblemFactRemoved(Object problemFact) {
124-
throw new UnsupportedOperationException();
125-
}
126-
127-
/**
128-
* @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences.
129-
* Use {@link ProblemChange} instead.
130-
*/
131-
@Deprecated(forRemoval = true, since = "1.8.0")
132-
default void afterProblemFactRemoved(Object problemFact) {
133-
throw new UnsupportedOperationException();
134-
}
135-
13646
/**
13747
* Translates an entity or fact instance (often from another {@link Thread} or JVM)
13848
* to this {@link ScoreDirector}'s internal working instance.

core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/gizmo/GizmoCloningUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static Set<Class<?>> getDeepClonedClasses(SolutionDescriptor<?> solutionD
4646
}
4747
}
4848

49-
// Ignore Collections, Maps, and PlanningCloneables, as there is collection/map/clonable logic to clone them.
49+
// Ignore Collections and Maps, as there is collection/map/clonable logic to clone them.
5050
if (DeepCloningUtils.isFieldDeepCloned(solutionDescriptor, field, clazz)
5151
&& !Collection.class.isAssignableFrom(field.getType())
5252
&& !Map.class.isAssignableFrom(field.getType())

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ShadowVariableUpdateHelper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ public InternalScoreDirectorFactory(SolutionDescriptor<Solution_> solutionDescri
317317
}
318318
}
319319

320+
@NullMarked
320321
private static class InternalScoreDirector<Solution_, Score_ extends Score<Score_>>
321322
extends AbstractScoreDirector<Solution_, Score_, InternalScoreDirectorFactory<Solution_, Score_>> {
322323

core/src/main/java/ai/timefold/solver/core/impl/move/MoveTesterScoreDirector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.jspecify.annotations.NullMarked;
1313

14+
@NullMarked
1415
final class MoveTesterScoreDirector<Solution_, Score_ extends Score<Score_>>
1516
extends AbstractScoreDirector<Solution_, Score_, MoveTesterScoreDirectorFactory<Solution_, Score_>> {
1617

core/src/main/java/ai/timefold/solver/core/impl/move/VariableChangeRecordingScoreDirector.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
import ai.timefold.solver.core.impl.score.director.ValueRangeManager;
1818
import ai.timefold.solver.core.impl.score.director.VariableDescriptorCache;
1919

20+
import org.jspecify.annotations.NullMarked;
2021
import org.jspecify.annotations.Nullable;
2122

23+
@NullMarked
2224
public final class VariableChangeRecordingScoreDirector<Solution_, Score_ extends Score<Score_>>
2325
implements RevertableScoreDirector<Solution_> {
2426

25-
private final InnerScoreDirector<Solution_, Score_> backingScoreDirector;
27+
private final @Nullable InnerScoreDirector<Solution_, Score_> backingScoreDirector;
2628
private final List<ChangeAction<Solution_>> variableChanges;
2729

2830
/*
@@ -42,7 +44,7 @@ public final class VariableChangeRecordingScoreDirector<Solution_, Score_ extend
4244
*
4345
* This map exists to ensure that this is the case.
4446
*/
45-
private final Map<Object, Integer> cache;
47+
private final @Nullable Map<Object, Integer> cache;
4648

4749
public VariableChangeRecordingScoreDirector(ScoreDirector<Solution_> backingScoreDirector) {
4850
this(backingScoreDirector, true);
@@ -56,8 +58,8 @@ public VariableChangeRecordingScoreDirector(ScoreDirector<Solution_> backingScor
5658
this.variableChanges = new LinkedList<>();
5759
}
5860

59-
private VariableChangeRecordingScoreDirector(InnerScoreDirector<Solution_, Score_> backingScoreDirector,
60-
List<ChangeAction<Solution_>> variableChanges, Map<Object, Integer> cache) {
61+
private VariableChangeRecordingScoreDirector(@Nullable InnerScoreDirector<Solution_, Score_> backingScoreDirector,
62+
List<ChangeAction<Solution_>> variableChanges, @Nullable Map<Object, Integer> cache) {
6163
this.backingScoreDirector = backingScoreDirector;
6264
this.variableChanges = variableChanges;
6365
this.cache = cache;
@@ -178,13 +180,13 @@ public SolutionDescriptor<Solution_> getSolutionDescriptor() {
178180

179181
@Override
180182
public ValueRangeManager<Solution_> getValueRangeManager() {
181-
return getBacking().getValueRangeManager();
183+
return Objects.requireNonNull(getBacking()).getValueRangeManager();
182184
}
183185

184186
/**
185187
* Returns the score director to which events are delegated.
186188
*/
187-
public InnerScoreDirector<Solution_, Score_> getBacking() {
189+
public @Nullable InnerScoreDirector<Solution_, Score_> getBacking() {
188190
return backingScoreDirector;
189191
}
190192

@@ -217,12 +219,12 @@ public void triggerVariableListeners() {
217219
}
218220

219221
@Override
220-
public <E> E lookUpWorkingObject(E externalObject) {
222+
public <E> @Nullable E lookUpWorkingObject(@Nullable E externalObject) {
221223
return Objects.requireNonNull(backingScoreDirector).lookUpWorkingObject(externalObject);
222224
}
223225

224226
@Override
225-
public <E> @Nullable E lookUpWorkingObjectOrReturnNull(E externalObject) {
227+
public <E> @Nullable E lookUpWorkingObjectOrReturnNull(@Nullable E externalObject) {
226228
return Objects.requireNonNull(backingScoreDirector).lookUpWorkingObjectOrReturnNull(externalObject);
227229
}
228230

core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import ai.timefold.solver.core.preview.api.move.Move;
4949
import ai.timefold.solver.core.preview.api.move.SolutionView;
5050

51-
import org.jspecify.annotations.NonNull;
5251
import org.jspecify.annotations.NullMarked;
5352
import org.jspecify.annotations.Nullable;
5453
import org.slf4j.Logger;
@@ -65,8 +64,9 @@
6564
* <li>after* method: first statement should be a call to the super method</li>
6665
* </ul>
6766
*/
67+
@NullMarked
6868
public abstract class AbstractScoreDirector<Solution_, Score_ extends Score<Score_>, Factory_ extends AbstractScoreDirectorFactory<Solution_, Score_, Factory_>>
69-
implements InnerScoreDirector<Solution_, Score_>, Cloneable {
69+
implements InnerScoreDirector<Solution_, Score_> {
7070

7171
private static final int CONSTRAINT_MATCH_DISPLAY_LIMIT = 8;
7272
protected final Logger logger = LoggerFactory.getLogger(getClass());
@@ -79,7 +79,7 @@ public abstract class AbstractScoreDirector<Solution_, Score_ extends Score<Scor
7979
*/
8080
private final NeighborhoodNotifier<Solution_> neighborhoodsElementUpdateNotifier;
8181
private final boolean lookUpEnabled;
82-
private final LookUpManager lookUpManager;
82+
private final @Nullable LookUpManager lookUpManager;
8383
protected final ConstraintMatchPolicy constraintMatchPolicy;
8484
private boolean expectShadowVariablesInCorrectState;
8585
private final VariableDescriptorCache<Solution_> variableDescriptorCache;
@@ -93,14 +93,14 @@ public abstract class AbstractScoreDirector<Solution_, Score_ extends Score<Scor
9393
* and operations which do not perform moves do not require them.
9494
*/
9595
private final ValueRangeManager<Solution_> valueRangeManager;
96-
private final ListVariableStateSupply<Solution_, Object, Object> listVariableStateSupply; // Null when no list variable.
96+
private final @Nullable ListVariableStateSupply<Solution_, Object, Object> listVariableStateSupply; // Null when no list variable.
9797
private final MoveDirector<Solution_, Score_> moveDirector = new MoveDirector<>(this);
9898

9999
private long workingEntityListRevision = 0L;
100100
private int workingGenuineEntityCount = 0;
101101
private boolean allChangesWillBeUndoneBeforeStepEnds = false;
102102
private long calculationCount = 0L;
103-
protected Solution_ workingSolution;
103+
protected @Nullable Solution_ workingSolution;
104104
private int workingInitScore = 0;
105105

106106
private final boolean isStepAssertOrMore;
@@ -178,7 +178,7 @@ public boolean expectShadowVariablesInCorrectState() {
178178
}
179179

180180
@Override
181-
public @NonNull Solution_ getWorkingSolution() {
181+
public Solution_ getWorkingSolution() {
182182
return workingSolution;
183183
}
184184

@@ -251,7 +251,8 @@ public NeighborhoodNotifier<Solution_> getNeighborhoodNotifier() {
251251
* @param workingSolution the working solution to set
252252
* @param entityAndFactVisitor maybe null; a function to apply to all problem facts and problem entities
253253
*/
254-
protected void setWorkingSolutionWithoutUpdatingShadows(Solution_ workingSolution, Consumer<Object> entityAndFactVisitor) {
254+
protected void setWorkingSolutionWithoutUpdatingShadows(Solution_ workingSolution,
255+
@Nullable Consumer<Object> entityAndFactVisitor) {
255256
this.workingSolution = requireNonNull(workingSolution);
256257
var solutionDescriptor = getSolutionDescriptor();
257258

@@ -443,15 +444,6 @@ protected void setCalculatedScore(Score_ score) {
443444
calculationCount++;
444445
}
445446

446-
/**
447-
* @deprecated Unused, but kept for backward compatibility.
448-
*/
449-
@Deprecated(forRemoval = true, since = "1.14.0")
450-
@Override
451-
public AbstractScoreDirector<Solution_, Score_, Factory_> clone() {
452-
throw new UnsupportedOperationException("Cloning score directors is not supported.");
453-
}
454-
455447
@Override
456448
public InnerScoreDirector<Solution_, Score_> createChildThreadScoreDirector(ChildThreadType childThreadType) {
457449
// Most score directors don't need derived status; CS will override this.
@@ -885,7 +877,7 @@ private void assertValueRangeForListVariable(Object entity, List<Object> valueLi
885877
}
886878

887879
private static <Solution_> void assertValueRangeForBasicVariables(InnerScoreDirector<Solution_, ?> scoreDirector,
888-
List<BasicVariableDescriptor<Solution_>> basicVariableDescriptorList, Object entity) {
880+
@Nullable List<BasicVariableDescriptor<Solution_>> basicVariableDescriptorList, Object entity) {
889881
if (basicVariableDescriptorList == null || basicVariableDescriptorList.isEmpty()) {
890882
return;
891883
}
@@ -905,7 +897,7 @@ private static <Solution_> void assertValueRangeForBasicVariables(InnerScoreDire
905897
}
906898

907899
private static <Solution_> void assertValueRangeForListVariable(InnerScoreDirector<Solution_, ?> scoreDirector,
908-
ListVariableDescriptor<Solution_> variableDescriptor, Object entity, List<Object> valueList) {
900+
ListVariableDescriptor<Solution_> variableDescriptor, Object entity, List<@Nullable Object> valueList) {
909901
if (valueList.isEmpty()) {
910902
return;
911903
}
@@ -923,36 +915,6 @@ private static <Solution_> void assertValueRangeForListVariable(InnerScoreDirect
923915
}
924916
}
925917

926-
public SolutionTracker.SolutionCorruptionResult getSolutionCorruptionAfterUndo(Move<Solution_> move,
927-
InnerScore<Score_> undoInnerScore) {
928-
var trackingWorkingSolution = solutionTracker != null;
929-
if (trackingWorkingSolution) {
930-
solutionTracker.setAfterUndoSolution(workingSolution);
931-
}
932-
// Precondition: assert that there are probably no corrupted constraints
933-
var undoMoveToString = "Undo(%s)".formatted(move);
934-
assertWorkingScoreFromScratch(undoInnerScore, undoMoveToString);
935-
// Precondition: assert that shadow variables aren't stale after doing the undoMove
936-
assertShadowVariablesAreNotStale(undoInnerScore, undoMoveToString);
937-
if (trackingWorkingSolution) {
938-
// Recalculate all shadow variables from scratch.
939-
// We cannot set all shadow variables to null, since some variable listeners
940-
// may expect them to be non-null.
941-
// Instead, we just simulate a change to all genuine variables.
942-
variableListenerSupport.forceTriggerAllVariableListeners(workingSolution);
943-
solutionTracker.setUndoFromScratchSolution(workingSolution);
944-
945-
// Also calculate from scratch for the before solution, since it might
946-
// have been corrupted but was only detected now
947-
solutionTracker.restoreBeforeSolution();
948-
variableListenerSupport.forceTriggerAllVariableListeners(workingSolution);
949-
solutionTracker.setBeforeFromScratchSolution(workingSolution);
950-
951-
return solutionTracker.buildSolutionCorruptionResult();
952-
}
953-
return SolutionTracker.SolutionCorruptionResult.untracked();
954-
}
955-
956918
/**
957919
* @param uncorruptedScoreDirector never null
958920
* @param predicted true if the score was predicted and might have been calculated on another thread
@@ -1028,11 +990,15 @@ Maybe there is a bug in the score constraints of those ConstraintMatch(s).
1028990
}
1029991

1030992
private static <Score_ extends Score<Score_>> List<MatchAnalysis<Score_>>
1031-
emptyMatchAnalysisIfNull(ConstraintAnalysis<Score_> constraintAnalysis) {
993+
emptyMatchAnalysisIfNull(@Nullable ConstraintAnalysis<Score_> constraintAnalysis) {
1032994
if (constraintAnalysis == null) {
1033995
return Collections.emptyList();
1034996
}
1035-
return Objects.requireNonNullElse(constraintAnalysis.matches(), Collections.emptyList());
997+
var matches = constraintAnalysis.matches();
998+
if (matches == null) {
999+
return Collections.emptyList();
1000+
}
1001+
return matches;
10361002
}
10371003

10381004
private void appendAnalysis(StringBuilder analysis, String workingLabel, String suffix,

core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@
4141
import ai.timefold.solver.core.preview.api.move.Move;
4242
import ai.timefold.solver.core.preview.api.move.SolutionView;
4343

44+
import org.jspecify.annotations.NullMarked;
4445
import org.jspecify.annotations.Nullable;
4546

4647
/**
4748
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
4849
* @param <Score_> the score type to go with the solution
4950
*/
51+
@NullMarked
5052
public interface InnerScoreDirector<Solution_, Score_ extends Score<Score_>>
5153
extends VariableDescriptorAwareScoreDirector<Solution_>, AutoCloseable {
5254

core/src/main/java/ai/timefold/solver/core/impl/score/director/RevertableScoreDirector.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import java.util.List;
44

5+
import org.jspecify.annotations.NullMarked;
6+
7+
@NullMarked
58
public interface RevertableScoreDirector<Solution_> extends VariableDescriptorAwareScoreDirector<Solution_> {
69

710
/**

0 commit comments

Comments
 (0)