mvn clean org.openrewrite.maven:rewrite-maven-plugin:4.44.0:run -Drewrite.recipeArtifactCoordinates=org.optaplanner:optaplanner-migration:9.44.0.Final -Drewrite.activeRecipes=org.optaplanner.migration.ToLatest9
OptaPlanner’s public API classes are backwards compatible (per series), but users often also use impl classes (which are documented in the reference manual too). This upgrade recipe minimizes the pain to upgrade your code and to take advantage of the newest features in OptaPlanner.
Every upgrade note has an indication how likely your code will be affected by that change:
To upgrade from an older version, first apply the previous upgrade recipes. You will find the order of migration steps bellow:
The RHDM version differs from the OptaPlanner version:
RHDM version | OptaPlanner version |
---|---|
7.8 | 7.39 |
7.9 | 7.44 |
7.1 | 7.48 |
7.11 | 8.5 (and 7.52) |
7.12 | 8.11 (and 7.59) |
7.13 | 8.13 (and 7.67) |
Update your code in seconds, with optaplanner-migration
(an OpenRewrite recipe). Try it:
mvn clean org.openrewrite.maven:rewrite-maven-plugin:4.44.0:run -Drewrite.recipeArtifactCoordinates=org.optaplanner:optaplanner-migration:9.44.0.Final -Drewrite.activeRecipes=org.optaplanner.migration.ToLatest9
Note: The -Drewrite.recipeArtifactCoordinates might not work,
use the more verbose pom.xml
approach instead.
It only does upgrade steps with an Automated badge.
ScoreDefinition
: ScoreHolder.register*ConstraintMatch
refactoredIf you have a custom ScoreDefinition
: the methods ScoreHolder.register*ConstraintMatch
have been refactored.
Before in *.java
:
public void addConstraintMatch(RuleContext kcontext, final int weight) {
...
registerIntConstraintMatch(kcontext, 0, weight, new Runnable() {
public void run() {
...
}
});
}
After in *.java
:
public void addConstraintMatch(RuleContext kcontext, final int weight) {
...
registerIntConstraintMatch(kcontext, 0, weight, new IntConstraintUndoListener() {
public void undo() {
...
}
});
}
Move
: extract AbstractMove
If you have a custom Move
implementation, now extract AbstractMove
Before in *.java
:
public class CloudComputerChangeMove implements Move {...}
After in *.java
:
public class CloudComputerChangeMove extends AbstractMove {...}
Move
: new method getSimpleMoveTypeDescription()
The interface Move
has a new method getSimpleMoveTypeDescription()
.
Extend AbstractMove
so to avoid having to implement it.
@ValueRangeProvider
on an entity class: use pillar selectors as isIf you have a @ValueRangeProvider
on an entity class (instead of the Solution
class),
then it’s now safe to use the <pillarChangeMoveSelector>
and <pillarSwapMoveSelector>
as is.
It’s no longer needed to filter out swaps or changes
which could put a value in an entity’s variable that’s not in its value range.
Before in *SolverConfig.xml
and *BenchmarkConfig.xml
:
<pillarChangeMoveSelector>
<filterClass>...ValidChangesOnlyPillarChangeMoveFilter</filterClass>
</pillarChangeMoveSelector>
<pillarSwapMoveSelector>
<filterClass>...ValidSwapsOnlyPillarSwapMoveFilter</filterClass>
</pillarSwapMoveSelector>
After in *SolverConfig.xml
and *BenchmarkConfig.xml
:
<pillarChangeMoveSelector/>
<pillarSwapMoveSelector/>
ConstraintMatchTotal
natural comparison changedConstraintMatchTotal
are now naturally compared by scoreLevel
, then constraintPackage
, then constraintName
(instead of by constraintPackage
, then constraintName
, then scoreLevel
) for readability.
IncrementalScoreCalculator
: method buildScoreCorruptionAnalysis(…)
replacedThe optional method IncrementalScoreCalculator.buildScoreCorruptionAnalysis(IncrementalScoreCalculator)
has been removed.
Instead, to get a pretty score corruption analysis, implement the new interface ConstraintMatchAwareIncrementalScoreCalculator
.
This also enable your GUI to explain the score with an IncrementalScoreCalculator
.
See the example code in MachineReassignmentIncrementalScoreCalculator.getConstraintMatchTotals()
.
<deciderScoreComparatorFactory>
removedThe element <deciderScoreComparatorFactory>
(which was deprecated, not documented, broken and clearly marked as not backwards compatible) has been removed.
Instead, use strategic oscillation.
Before in *SolverConfig.xml
and *BenchmarkConfig.xml
:
<localSearch>
...
<forager>
...
<deciderScoreComparatorFactory>
...
</deciderScoreComparatorFactory>
</forager>
</localSearch>
After in *SolverConfig.xml
and *BenchmarkConfig.xml
:
<localSearch>
...
<forager>
...
<finalistPodiumType>STRATEGIC_OSCILLATION</finalistPodiumType>
</forager>
</localSearch>
ScoreBounder
methods changedThe ScoreBounder
methods calculateOptimisticBound()
and calculatePessimisticBound()
no longer have an uninitializedVariableCount
parameter.
Instead, if all the variables for a branch and bound algorithm are initialized,
those methods are no longer called to determine the bounds (because the bound is the working score).
If the uninitializedVariableCount
is still needed for some reason, use the ScoreDirector
to calculate it accurately.
ScoreDirector.getConstraintMatchTotals()
behaviour changedBefore calling ScoreDirector.getConstraintMatchTotals()
, it’s no longer expected to call ScoreDirector.calculateScore()
first.
CompositeMove
now uses a Move
arrayCompositeMove
now uses a Move
array instead of a List<Move>
for performance reasons.
Before in *.java
:
... = CompositeMove.buildMove(Arrays.asList(moveA, moveB, ...));
After in *.java
:
... = CompositeMove.buildMove(moveA, moveB, ...);
Before in *.java
:
... = new CompositeMove(moveList); // Not recommended
After in *.java
:
... = new CompositeMove(moves); // Not recommended
InverseRelationShadowVariableListener
renamedInverseRelationShadowVariableListener
renamed to SingletonInverseVariableListener
.
It and InverseRelationShadowVariableDescriptor
moved to the package …impl.domain.variable.inverserelation
.
There is now out-of-the-box support for a shadow variable representing the anchor of a chained variable.
For example, in a VRP each Customer
(= entity) needs to know to which Vehicle
(= anchor) it belongs.
This declarative support allows built-in selectors to reuse that knowledge without duplicating the calculation.
Before in *.java
:
@PlanningEntity
public class Customer implements Standstill {
@PlanningVariable(...)
public Standstill getPreviousStandstill() {...}
@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Vehicle getVehicle() {...}
}
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
...
}
After in *.java
:
@PlanningEntity
public class Customer implements Standstill {
@PlanningVariable(...)
public Standstill getPreviousStandstill() {...}
@AnchorShadowVariable(sourceVariableName = "previousStandstill")
public Vehicle getVehicle() {...}
}
<twoOptMoveSelector>
replacedThe undocumented, experimental <twoOptMoveSelector>
has been replaced by <tailChainSwapMoveSelector>
,
which is documented.
To scale VRP cases, Nearby Selection is critical. It is now finally completely supported and documented.