Chapter 1. Changes that are not compatible with OptaPlanner 7.x or earlier
The changes listed in the section are not compatible with OptaPlanner 7.x or earlier versions of OptaPlanner.
Java 11 or higher required
Major, Public API
If you are using JRE or JDK 8, upgrade to JDK 11 or higher.
On Linux, get OpenJDK from your Linux software repository. On Fedora and Red Hat Enterprise Linux, enter the following command:
sudo dnf install java-11-openjdk-devel
- On Windows and macOS, download OpenJDK from the AdoptOpenJDK website.
SolverFactory
and PlannerBenchmarkFactory
no longer support KIE containers
Major, Public API
Because OptaPlanner now aligns with Kogito, the KIE container concept no longer applies. Therefore, SolverFactory
no longer allows you to create Solver
instances from KIE containers. This also applies to PlannerBenchmarkFactory
and benchmarks.
OSGi metadata removed
Major, Public API
Because of the limited usage of OSGi and the maintenance burden it brings, the OptaPlanner JAR files in the OptaPlanner 8.x series no longer include OSGi metadata in their META-INF/MANIFEST.MF
file.
Refrain from using Java serialization
Minor, Public API
In OptaPlanner 8, most uses of the Serializable
marker interface were removed from the public API. Consider serializing with JSON or another format.
SolverFactory.getScoreDirectorFactory()
replaced with ScoreManager
Major, Public API
In version 7 of OptaPlanner, using ScoreDirectorFactory
was necessary in order to explain the score. In version 8 of OptaPlanner, new functionality was added to the ScoreManager
and as a result there is no longer any reason to create new instances of ScoreDirector
.
An example from a *.java
file in OptaPlanner 7:
ScoreDirectorFactory<CloudBalance> scoreDirectorFactory = solverFactory.getScoreDirectorFactory(); try (ScoreDirector<CloudBalance> scoreDirector = scoreDirectorFactory.buildScoreDirector()) { scoreDirector.setWorkingSolution(solution); Score score = scoreDirector.calculateScore(); }
An example from a *.java
file in OptaPlanner 8:
ScoreManager<CloudBalance> scoreManager = ScoreManager.create(solverFactory); Score score = scoreManager.updateScore(solution);
Methods that allowed you to retrieve an instance of ScoreDirector
and ScoreDirectorFactory
have been removed from the public API without replacement. A reduced version of the ScoreDirector
interface was promoted to the public API to promote the ProblemFactChange
interface to the public API.
SolverFactory
: getSolverConfig()
removed
Minor, Public API
The SolverFactory.getSolverConfig()
method has been deprecated and replaced with the SolverFactory.create(SolverConfig)
method. A SolverConfig
instance is now instantiated before a SolverFactory
instance is instantiated, which is more natural. The previous order has been removed.
An example from a *.java
file in OptaPlanner 7:
SolverFactory<MySolution> solverFactory = SolverFactory.createFromXmlResource(".../mySolverConfig.xml"); SolverConfig solverConfig = solverFactory.getSolverConfig(); ... Solver<MySolution> solver = solverFactory.buildSolver();
An example from a *.java
file in OptaPlanner 8:
SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver();
If you were also passing a ClassLoader
, pass it to both SolverConfig.createFromXmlResource()
and SolverFactory.create()
.
SolverConfig
: buildSolver()
removed
Minor, Public API
The SolverConfig.buildSolver()
method is an inner method that does not belong in the public API. Use the SolverFactory.buildSolver()
method instead.
An example from a *.java
file in OptaPlanner 7:
SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... Solver<MySolution> solver = solverConfig.buildSolver();
An example from a *.java
file in OptaPlanner 8:
SolverConfig solverConfig = SolverConfig.createFromXmlResource(".../mySolverConfig.xml"); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver();
PlannerBenchmarkConfig
: buildPlannerBenchmark()
removed
Minor, Public API
The PlannerBenchmarkConfig.buildPlannerBenchmark()
method is an inner method that does not belong in the public API. Use the PlannerBenchmarkFactory.buildPlannerBenchmark()
method instead.
An example from a *.java
file in OptaPlanner 7:
PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
An example from a *.java
file in OptaPlanner 8:
PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
SolverFactory
: cloneSolverFactory()
removed
Minor, Public API
The SolverFactory.cloneSolverFactory()
method has been deprecated and replaced with the new SolverConfig(SolverConfig)
copy constructors and the SolverFactory.cloneSolverFactory()
method has been removed.
An example from a *.java
file in OptaPlanner 7:
private SolverFactory<MySolution> base; public void userRequest(..., long userInput) { SolverFactory<MySolution> solverFactory = base.cloneSolverFactory(); solverFactory.getSolverConfig() .getTerminationConfig() .setMinutesSpentLimit(userInput); Solver<MySolution> solver = solverFactory.buildSolver(); ... }
An example from a *.java
file in OptaPlanner 8:
private SolverConfig base; public void userRequest(..., long userInput) { SolverConfig solverConfig = new SolverConfig(base); // Copy it solverConfig.getTerminationConfig() .setMinutesSpentLimit(userInput); SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver(); ... }
SolverFactory
: createEmpty()
removed
Minor, Public API
The SolverFactory.createEmpty()
method has been deprecated and replaced with the new SolverConfig()
method. The SolverFactory.createEmpty()
method has been removed.
An example from a *.java
file in OptaPlanner 7:
SolverFactory<MySolution> solverFactory = SolverFactory.createEmpty(); SolverConfig solverConfig = solverFactory.getSolverConfig() ... Solver<MySolution> solver = solverFactory.buildSolver();
An example from a *.java
file in OptaPlanner 8:
SolverConfig solverConfig = new SolverConfig(); ... SolverFactory<MySolution> solverFactory = SolverFactory.create(solverConfig); Solver<MySolution> solver = solverFactory.buildSolver();
XML <solver/> root element now belongs to the https://www.optaplanner.org/xsd/solver namespace
Major, Public API
OptaPlanner now provides an XML schema definition for the solver configuration. Although OptaPlanner retains compatibility with previous versions of the existing XML configuration, migrating to the XSD is strongly recommended because OptaPlanner might support only valid configuration XML in the future.
An example from the *SolverConfig.xml
file in OptaPlanner 7:
<?xml version="1.0" encoding="UTF-8"?> <solver> ... </solver>
An example from the *SolverConfig.xml
file in OptaPlanner 8:
<?xml version="1.0" encoding="UTF-8"?> <solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd"> ... </solver>
Using the XSD might require reordering some of the XML elements of the configuration. Use code completion in the IDE to migrate to a valid XML.
Property subPillarEnabled
in move selector configuration has been removed
Minor, Public API
The subPillarEnabled
property on PillarSwapMoveSelector
and PillarChangeMoveSelector
has been deprecated and replaced with a new property, subPillarType
. The subPillarEnabled
property has been removed.
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 7:
<pillar...MoveSelector> ... <pillarSelector> <subPillarEnabled>false</subPillarEnabled> ... </pillarSelector> ... </pillar...MoveSelector>
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 8:
<pillar...MoveSelector> <subPillarType>NONE</subPillarType> <pillarSelector> ... </pillarSelector> ... </pillar...MoveSelector>
Solver
: getScoreDirectorFactory()
removed
Major, Public API
The getScoreDirectorFactory()
method has been deprecated and has now been removed from both Solver
and SolverFactory
classes.
You no longer need to create a Solver
instance just to calculate or explain a score in the UI. Use the ScoreManager
API instead.
An example from a *.java
file in OptaPlanner 7:
SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); Solver<VehicleRoutingSolution> solver = solverFactory.buildSolver(); uiScoreDirectorFactory = solver.getScoreDirectorFactory(); ...
An example from a *.java
file in OptaPlanner 8:
SolverFactory<VehicleRoutingSolution> solverFactory = SolverFactory.createFromXmlResource(...); ScoreManager<VehicleRoutingSolution> scoreManager = ScoreManager.create(solverFactory); ...
ScoreDirectorFactory
should not be used anymore because it has always been outside the public API and all of its functionality is exposed in various parts of the public API.
Solver.explainBestScore()
has been removed
Major, Public API
The explainBestScore()
method on the Solver
interface was deprecated in 7.x and has now been removed. You can obtain the same information through the new ScoreManager
API.
Red Hat recommends that you do not parse the results of this method call in any way.
An example from a *.java
file in OptaPlanner 7:
solver = ...; scoreExplanation = solver.explainBestScore();
An example from a *.java
file in OptaPlanner 8:
MySolution solution = ...; ScoreManager<MySolution> scoreManager = ...; scoreExplanation = scoreManager.explainScore(solution);
The Solver interface methods getBestSolution()
, getBestScore()
, and getTimeMillisSpent()
have been removed
Minor, Public API
Several methods on the Solver
interface were deprecated in 7.x and have been removed. You can obtain the same information by registering an EventListener
through the Solver.addEventListener(…)
.
An example from a *.java
file in OptaPlanner 7:
solver = ...; solution = solver.getBestSolution(); score = solver.getBestScore(); timeMillisSpent = solver.getTimeMillisSpent();
An example from a *.java
file in OptaPlanner 8:
solver = ...; solver.addEventListener(event -> { solution = event.getNewBestSolution(); score = event.getNewBestScore(); timeMillisSpent = event.getTimeMillisSpent(); });
Annotation scanning has been removed
Major, Public API
The <scanAnnotatedClasses/>
directive in the solver configuration was deprecated in 7.x and is now removed.
An example from the *.xml
file in OptaPlanner 7:
<solver> ... <scanAnnotatedClasses/> ... </solver>
An example from the *.xml
file in OptaPlanner 8:
<solver> ... <solutionClass>...</solutionClass> <entityClass>...</entityClass> ... </solver>
New package for @PlanningFactProperty
and @PlanningFactCollectionProperty
Major, Public API
The @PlanningFactProperty
and @PlanningFactCollectionProperty
annotations now share the same package with other similar annotations, such as @PlanningSolution
. The old annotations were deprecated in 7.x and removed.
An example from a *.java
file in OptaPlanner 7:
import org.optaplanner.core.api.domain.solution.drools.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.drools.ProblemFactProperty;
An example from a *.java
file in OptaPlanner 8:
import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; import org.optaplanner.core.api.domain.solution.ProblemFactProperty;
filterClassList
replaced with a single filter class
Minor, Public API
The configuration of EntitySelector
, ValueSelector
, and MoveSelector
now has a single filter class in both the configuration API and the solver configuration XML.
In practice, you do not need multiple selection filter classes often, and you can replace them with a single selection filter class that implements the logic of all of them. Passing a single selection class now requires less boilerplate code.
An example from a *.java
file in OptaPlanner 7:
ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClassList(Collections.singletonList(MySelectionFilterClass.class));
An example from a *.java
file in OptaPlanner 8:
ValueSelectorConfig valueSelectorConfig = new ValueSelectorConfig(); valueSelectorConfig.setFilterClass(MySelectionFilterClass.class);
Replacing multiple selection filter classes with a single selection filter class
An example from the *.xml
file in OptaPlanner 7:
<swapMoveSelector> <entitySelector> <filterClass>com.example.FilterA</filterClass> <filterClass>com.example.FilterB</filterClass> </entitySelector> </swapMoveSelector>
An example from a *.java
file in OptaPlanner 7:
package com.example; ... public class FilterA implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500; } }
package com.example; ... public class FilterB implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getOrder() == Order.ASC; } }
An example from the *.xml
file in OptaPlanner 8:
<swapMoveSelector> <entitySelector> <filterClass>com.example.SingleEntityFilter</filterClass> </entitySelector> </swapMoveSelector>
An example from a *.java
file in OptaPlanner 8:
package com.example; ... public class SingleEntityFilter implements SelectionFilter<MySolution, MyPlanningEntity> { @Override public boolean accept(ScoreDirector<MySolution> scoreDirector, MyPlanningEntity selection) { return selection.getValue() < 500 && selection.getOrder() == Order.ASC; } }
AcceptorConfig
renamed to LocalSearchAcceptorConfig
Minor
This only impacts the configuration API. The solver configuration XML file remains intact.
Naming consistency with other local-search-specific configuration classes has been implemented.
An example from a *.java
file in OptaPlanner 7:
LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new AcceptorConfig().withEntityTabuSize(5));
An example from a *.java
file in OptaPlanner 8:
LocalSearchPhaseConfig localSearchPhaseConfig = new LocalSearchPhaseConfig() .withAcceptorConfig(new LocalSearchAcceptorConfig().withEntityTabuSize(5));
Custom properties XML configuration format changes
Minor, Public API
This issue only impacts the solver configuration XML, specifically <scoreDirectorFactory/>
, <moveIteratorFactory/>
, <moveListFactory/>
, <partitionedSearch/>
and <customPhase/>
.
This change was made to enforce the structure of the configuration XML in build time.
An example from the *.xml
file in OptaPlanner 7:
<partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <partCount>4</partCount> <!-- a custom property --> <minimumProcessListSize>300</minimumProcessListSize> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch>
An example from the *.xml
file in OptaPlanner 8:
<partitionedSearch> <solutionPartitionerClass>com.example.MySolutionPartitioner</solutionPartitionerClass> <solutionPartitionerCustomProperties> <property name="partCount" value="4"/> <!-- a custom property --> <property name="minimumProcessListSize" value="300"/> <!-- a custom property --> </solutionPartitionerCustomProperties> </partitionedSearch>
<variableNameInclude/>
elements are now wrapped by the <variableNameIncludes/>
element
Minor, Public API
This update only impacts the solver configuration XML, specifically the <swapMoveSelector/>
and <pillarSwapMoveSelector/>
.
This change was made to enforce the structure of the configuration XML in build time.
An example from the *.xml
file in OptaPlanner 7:
<swapMoveSelector> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </swapMoveSelector>
An example from the *.xml
file in OptaPlanner 8:
<swapMoveSelector> <variableNameIncludes> <variableNameInclude>variableA</variableNameInclude> <variableNameInclude>variableB</variableNameInclude> </variableNameIncludes> </swapMoveSelector>
Solution
interface removed
Minor, Public API
The Solution
interface was deprecated and removed. The AbstractSolution
interface which is only used by Business Central has also been removed.
Remove the Solution
interface, annotate the getScore()
method with @PlanningScore
, and replace the getProblemFacts()
method with a @ProblemFactCollectionProperty
annotation directly on every problem fact getter (or field).
An example from a *.java
file in OptaPlanner 7:
@PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private List<CloudComputer> computerList; ... private HardSoftScore score; @ValueRangeProvider(id = "computerRange") public List<CloudComputer> getComputerList() {...} public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.addAll(computerList); ... return facts; } }
An example from a *.java
file in OptaPlanner 8:
@PlanningSolution public class CloudBalance { private List<CloudComputer> computerList; ... private HardSoftScore score; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty public List<CloudComputer> getComputerList() {...} @PlanningScore public HardSoftScore getScore() {...} public void setScore(HardSoftScore score) {...} }
For a single problem fact that is not wrapped in a Collection
, use the @ProblemFactProperty
annotation, as shown in the following example, with field annotations this time:
An example from a *.java
file in OptaPlanner 7:
@PlanningSolution public class CloudBalance implements Solution<HardSoftScore> { private CloudParametrization parametrization; private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") private List<CloudComputer> computerList; ... public Collection<? extends Object> getProblemFacts() { List<Object> facts = new ArrayList<Object>(); facts.add(parametrization); // not a Collection facts.addAll(buildingList); facts.addAll(computerList); ... return facts; } }
An example from a *.java
file in OptaPlanner 8:
@PlanningSolution public class CloudBalance { @ProblemFactProperty private CloudParametrization parametrization; @ProblemFactCollectionProperty private List<CloudBuilding> buildingList; @ValueRangeProvider(id = "computerRange") @ProblemFactCollectionProperty private List<CloudComputer> computerList; ... }
Do not add the @ProblemFactCollectionProperty
annotation on getters (or fields) that have a @PlanningEntityCollectionProperty
annotation.
BestSolutionChangedEvent
: isNewBestSolutionInitialized()
removed
Minor, Public API
The BestSolutionChangedEvent.isNewBestSolutionInitialized()
method has been deprecated and replaced with the BestSolutionChangedEvent.getNewBestSolution().getScore().isSolutionInitialized()
method. The BestSolutionChangedEvent.isNewBestSolutionInitialized()
method has been removed.
An example from a *.java
file in OptaPlanner 7:
public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.isNewBestSolutionInitialized()) { ... } }
An example from a *.java
file in OptaPlanner 8:
public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() && event.getNewBestSolution().getScore().isSolutionInitialized()) { ... } }
If you check isFeasible()
, it checks if the solution is initialized.
An example from a *.java
file in OptaPlanner 8:
public void bestSolutionChanged(BestSolutionChangedEvent<CloudBalance> event) { if (event.isEveryProblemFactChangeProcessed() // isFeasible() checks isSolutionInitialized() too && event.getNewBestSolution().getScore().isFeasible()) { ... } }
<valueSelector>
: variableName
is now an attribute
Minor, Public API
When power-tweaking move selectors, such as <changeMoveSelector>
, in a use case with multiple planning variables, the <variableName>
XML element has been replaced with a variableName="…"
XML attribute. This change reduces the solver configuration verbosity. After being deprecated for the entire 7.x series, the old way has now been removed.
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 7:
<valueSelector> <variableName>room</variableName> </valueSelector>
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 8:
<valueSelector variableName="room"/>
Partitioned Search: threadFactoryClass
removed
Minor, Public API
Because <solver>
has supported a <threadFactoryClass>
element for some time, the <threadFactoryClass>
element under <partitionedSearch>
has been removed.
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 7:
<solver> ... <partitionedSearch> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> ... </partitionedSearch> </solver>
An example from the *SolverConfig.xml
and *BenchmarkConfig.xml
files in OptaPlanner 8:
<solver> <threadFactoryClass>...MyAppServerThreadFactory</threadFactoryClass> ... <partitionedSearch> ... </partitionedSearch> </solver>
SimpleDoubleScore
and HardSoftDoubleScore
removed
Minor, Public API
The use of double-based score types is not recommended because they can cause score corruption. They have been removed.
An example from a *.java
file in OptaPlanner 7:
@PlanningSolution public class MyPlanningSolution { private SimpleDoubleScore score; ... }
An example from a *.java
file in OptaPlanner 8:
@PlanningSolution public class MyPlanningSolution { private SimpleLongScore score; ... }
Score.toInitializedScore()
removed
Minor, Public API
The Score.toInitializedScore()
method was deprecated and replaced with the Score.withInitScore(int)
method in 7.x and is now removed.
An example from a *.java
file in OptaPlanner 7:
score = score.toInitializedScore();
An example from a *.java
file in OptaPlanner 8:
score = score.withInitScore(0);
Various justification Comparators
removed
Minor, Public API
The following Comparator
implementations were deprecated in 7.x and now removed:
-
org.optaplanner.core.api.score.comparator.NaturalScoreComparator
-
org.optaplanner.core.api.score.constraint.ConstraintMatchScoreComparator
-
org.optaplanner.core.api.score.constraint.ConstraintMatchTotalScoreComparator
-
org.optaplanner.core.api.score.constraint.IndictmentScoreComparator
An example from a *.java
file in OptaPlanner 7:
NaturalScoreComparator comparator = new NaturalScoreComparator(); ConstraintMatchScoreComparator comparator2 = new ConstraintMatchScoreComparator();
An example from a *.java
file in OptaPlanner 8:
Comparator<Score> comparator = Comparable::compareTo; Comparator<ConstraintMatch> comparator2 = Comparator.comparing(ConstraintMatch::getScore);
FeasibilityScore
removed
Minor, Public API
The FeasibilityScore
interface was deprecated in 7.x and its only method isFeasible()
moved to the Score
supertype. The interface has now been removed.
You should refer to Score
s by their ultimate type, for example HardSoftScore
instead of to Score
.
@PlanningEntity.movableEntitySelectionFilter
removed
Minor, Public API
The movableEntitySelectionFilter
field on the @PlanningEntity
annotation was deprecated in 7.x and a new field pinningFilter
has been introduced with a name that shows the relation to the @PlanningPin
annotation. This filter implements a new PinningFilter
interface, returning true if the entity is pinned, and false if movable. The logic of this new filter is therefore inverted as compared to the old filter.
You should update your @PlanningEntity
annotations by supplying the new filter instead of the old filter. The old filter has now been removed.
An example from a *.java
file in OptaPlanner 7:
@PlanningEntity(movableEntitySelectionFilter = MyMovableEntitySelectionFilter.class)
An example from a *.java
file in OptaPlanner 8:
@PlanningEntity(pinningFilter = MyPinningFilter.class)
@PlanningVariable.reinitializeVariableEntityFilter
removed
Minor, Public API
The reinitializeVariableEntityFilter
field on the @PlanningVariable
annotation was deprecated in 7.x and now removed.
*ScoreHolder
classes turned into interfaces
Minor, Public API
In OptaPlanner 7, ScoreHolder
classes, used exclusively for Drools score calculation, exposed a number of public methods which, if used, allowed the user to unintentionally corrupt or otherwise negatively affect their scores.
In OptaPlanner 8, these methods have been removed and the classes have been turned into interfaces. Most users do not use the removed and potentially harmful methods.
However, if you do use these methods, you will find suitable replacements in the public API in areas of score explanation and constraint configuration.
ValueRangeFactory
class now final
Minor
ValueRangeFactory
class is a factory class that has only static methods. There is no need for you to extend this class, and it has therefore been made final
.
An example from a *.java
file in OptaPlanner 7:
class MyValueRangeFactory extends ValueRangeFactory { ... }
An example from a *.java
file in OptaPlanner 8:
class MyValueRangeFactory { ... }
ConstraintMatchTotal
and Indictment
are now interfaces
Minor, Public API
ConstraintMatchTotal
and Indictment
classes have been converted into interfaces. As a result, their implementations were moved out of the public API, together with methods that allowed them to mutate their state. These methods were never intended for the public API, and therefore there is no replacement for them.
You might still need the instances themselves if you choose to implement ConstraintMatchAwareIncrementalScoreCalculator
:
ConstraintMatchTotal maximumCapacityMatchTotal = new ConstraintMatchTotal(...);
An example from a *.java
file in OptaPlanner 8:
ConstraintMatchTotal maximumCapacityMatchTotal = new DefaultConstraintMatchTotal(...);
ScoreManager
: generic type Score
added
Major, Public API
The ScoreManager
and ScoreExplanation
APIs now have the generic type Score
to avoid downcasts in your code, for example from Score
to HardSoftScore
.
An example from a *.java
file in OptaPlanner 7:
@Inject // or @Autowired ScoreManager<TimeTable> scoreManager;
An example from a *.java
file in OptaPlanner 8:
@Inject // or @Autowired ScoreManager<TimeTable, HardSoftScore> scoreManager;
An example from a *.java
file in OptaPlanner 7:
ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = (HardSoftScore) explanation.getScore();
An example from a *.java
file in OptaPlanner 8:
ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); HardSoftScore score = explanation.getScore();
ConstraintMatchTotal
, ConstraintMatch
, and Indictment
: generic type Score
added
Major
Similar to ScoreManager
and ScoreExplanation
, the ConstraintMatchTotal
, ConstraintMatch
, and Indictment
APIs now have a generic type Score
to avoid downcasts in your code, for example from Score
to HardSoftScore
.
An example from a *.java
file in OptaPlanner 7:
ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = (HardSoftScore) constraintMatchTotal.getScore();
An example from a *.java
file in OptaPlanner 8:
ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<String, ConstraintMatchTotal<HardSoftScore>> constraintMatchTotalMap = scoreExplanation.getConstraintMatchTotalMap(); ConstraintMatchTotal<HardSoftScore> constraintMatchTotal = constraintMatchTotalMap.get(contraintId); HardSoftScore totalScore = constraintMatchTotal.getScore();
An example from a *.java
file in OptaPlanner 7:
ScoreExplanation<TimeTable> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment indictment = indictmentMap.get(lesson); HardSoftScore totalScore = (HardSoftScore) indictment.getScore();
An example from a *.java
file in OptaPlanner 8:
ScoreExplanation<TimeTable, HardSoftScore> explanation = scoreManager.explainScore(timeTable); Map<Object, Indictment<HardSoftScore>> indictmentMap = scoreExplanation.getIndictmentMap(); Indictment<HardSoftScore> indictment = indictmentMap.get(lesson); HardSoftScore totalScore = indictment.getScore();
ConstraintMatchAwareIncrementalScoreCalculator
: generic type Score
added
Minor
The interface ConstraintMatchAwareIncrementalScoreCalculator
now also has a generic type parameter for Score
to avoid raw type usages of ConstraintMatchTotal
and Indictment
.
An example from a *.java
file in OptaPlanner 7:
public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment> { @Override public Collection<ConstraintMatchTotal> getConstraintMatchTotals() { ... } @Override public Map<Object, Indictment> getIndictmentMap() { ... } }
An example from a *.java
file in OptaPlanner 8:
public class MachineReassignmentIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<MachineReassignment, HardSoftLongScore> { @Override public Collection<ConstraintMatchTotal<HardSoftLongScore>> getConstraintMatchTotals() { ... } @Override public Map<Object, Indictment<HardSoftLongScore>> getIndictmentMap() { ... } }
AbstractCustomPhaseCommand
was removed
Minor, Public API
The abstract class AbstractCustomPhaseCommand
was removed. Any class that extends it should directly implement the CustomPhaseCommand
interface.
An example from a *.java
file in OptaPlanner 7:
public class DinnerPartySolutionInitializer extends AbstractCustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { ... } }
An example from a *.java
file in OptaPlanner 8:
public class DinnerPartySolutionInitializer implements CustomPhaseCommand<DinnerParty> { @Override public void changeWorkingSolution(ScoreDirector<DinnerParty> scoreDirector) { ... } }
Score calculators moved to the public API
Major
The interfaces EasyScoreCalculator
, IncrementalScoreCalculator
, and ConstraintMatchAwareIncrementalScoreCalculator
have moved to a new package in the public API. Their deprecated counterparts have been removed. The deprecated class org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator
has also been removed. Replace the use of the removed interfaces and classes with their counterparts in the public API.
An example from the EasyScoreCalculator.java
file in OptaPlanner 7:
... import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator; ... public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> { ... }
An example from the EasyScoreCalculator.java
file in OptaPlanner 8:
... import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; ... public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance, HardSoftScore> { ... }
An example from the IncrementalScoreCalculator.java
file in OptaPlanner 7:
... import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; ... public class CloudBalancingIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CloudBalance> { ... }
An example from the IncrementalScoreCalculator.java
file in OptaPlanner 8:
... import org.optaplanner.core.api.score.calculator.IncrementalScoreCalculator; ... public class CloudBalancingIncrementalScoreCalculator implements IncrementalScoreCalculator<CloudBalance, HardSoftScore> { ... }
An example from the ConstraintMatchAwareIncrementalScoreCalculator.java
file in OptaPlanner 7:
... import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; import org.optaplanner.core.impl.score.director.incremental.ConstraintMatchAwareIncrementalScoreCalculator; ... public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CheapTimeSolution> implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution> { ... }
An example from the ConstraintMatchAwareIncrementalScoreCalculator.java
file in OptaPlanner 8:
... import org.optaplanner.core.api.score.calculator.ConstraintMatchAwareIncrementalScoreCalculator; ... public class CheapTimeConstraintMatchAwareIncrementalScoreCalculator implements ConstraintMatchAwareIncrementalScoreCalculator<CheapTimeSolution, HardMediumSoftLongScore> { ... }
PlannerBenchmarkFactory
: createFromSolverFactory()
removed
Major, Public API
The PlannerBenchmarkFactory.createFromSolverFactory()
method has been deprecated and replaced with the PlannerBenchmarkFactory.createFromSolverConfigXmlResource(String)
method. The PlannerBenchmarkFactory.createFromSolverFactory()
method has been removed.
An example from a *.java
file in OptaPlanner 7:
SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource( ".../cloudBalancingSolverConfig.xml"); PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverFactory(solverFactory);
An example from a *.java
file in OptaPlanner 8:
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromSolverConfigXmlResource( ".../cloudBalancingSolverConfig.xml");
If you programmatically adjust the solver configuration, you can use PlannerBenchmarkConfig.createFromSolverConfig(SolverConfig)
and then PlannerBenchmarkFactory.create(PlannerBenchmarkConfig)
instead.
PlannerBenchmarkFactory
: getPlannerBenchmarkConfig()
removed
Minor, Public API
The PlannerBenchmarkFactory.getPlannerBenchmarkConfig()
method has been deprecated and replaced with the PlannerBenchmarkFactory.create(PlannerBenchmarkConfig)
method. A PlannerBenchmarkConfig
instance is now instantiated before a PlannerBenchmarkFactory
instance is instantiated. This order is more logical. PlannerBenchmarkFactory.getPlannerBenchmarkConfig()
has been removed.
An example from a *.java
file in OptaPlanner 7:
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); PlannerBenchmarkConfig benchmarkConfig = benchmarkFactory.getPlannerBenchmarkConfig(); ... PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
An example from a *.java
file in OptaPlanner 8:
PlannerBenchmarkConfig benchmarkConfig = PlannerBenchmarkConfig.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); ... PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.create(benchmarkConfig); PlannerBenchmark benchmark = benchmarkFactory.buildPlannerBenchmark();
XML <plannerBenchmark/> root element now belongs to the https://www.optaplanner.org/xsd/benchmark namespace
Minor, Public API
OptaPlanner now provides an XML Schema Definition (XSD) for the benchmark configuration. Although OptaPlanner keeps compatibility with earlier versions of the existing XML configuration, migrating to the XSD is strongly recommended because OptaPlanner might support only valid configuration XML in the future.
An example from the *BenchmarkConfig.xml
file in OptaPlanner 7:
<?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark> ... </plannerBenchmark>
An example from the *BenchmarkConfig.xml
file in OptaPlanner 8:
<?xml version="1.0" encoding="UTF-8"?> <plannerBenchmark xmlns="https://www.optaplanner.org/xsd/benchmark" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.optaplanner.org/xsd/benchmark https://www.optaplanner.org/xsd/benchmark/benchmark.xsd"> ... </plannerBenchmark>
Using the XSD might require reordering some of the XML elements of the configuration. Use code completion in the IDE to migrate to a valid XML.
ProblemBenchmarksConfig
: xStreamAnnotatedClass
removed
Major, Public API
The <xStreamAnnotatedClass/>
has been removed from the <problemBenchmarks/>
configuration together with the corresponding getXStreamAnnotatedClassList()
and setXStreamAnnotatedClassList()
methods in the ProblemBenchmarksConfig
class.
An example from a *.java
file in OptaPlanner 7:
ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setXStreamAnnotatedClassList(MySolution.class);
An example from a *.java
file in OptaPlanner 8:
package com.example; ... public class MySolutionFileIO extends XStreamSolutionFileIO<MySolution> { public MySolutionFileIO() { super(MySolution.class); } } ... ProblemBenchmarksConfig problemBenchmarksConfig = new ProblemBenchmarksConfig(); problemBenchmarksConfig.setSolutionFileIOClass(MySolutionFileIO.class);
An example from the *BenchmarkConfig.xml
file in OptaPlanner 7:
<plannerBenchmark> ... <solverBenchmark> <problemBenchmarks> <xStreamAnnotatedClass>com.example.MySolution</xStreamAnnotatedClass> ... </problemBenchmarks> ... </solverBenchmark> ... </plannerBenchmark>
An example from the *BenchmarkConfig.xml
file in OptaPlanner 8:
<plannerBenchmark> ... <solverBenchmark> <problemBenchmarks> <!-- See the "After in *.java" section to create the MySolutionFileIO. --> <solutionFileIOClass>com.example.MySolutionFileIO</solutionFileIOClass> ... </problemBenchmarks> ... </solverBenchmark> ... </plannerBenchmark>
BenchmarkAggregatorFrame
: createAndDisplay(PlannerBenchmarkFactory)
removed
Minor
The BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkFactory)
method has been deprecated and replaced with the BenchmarkAggregatorFrame.createAndDisplayFromXmlResource(String)
method. The BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkFactory)
method has been removed.
An example from a *.java
file in OptaPlanner 7:
PlannerBenchmarkFactory benchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml"); BenchmarkAggregatorFrame.createAndDisplay(benchmarkFactory);
An example from a *.java
file in OptaPlanner 8:
BenchmarkAggregatorFrame.createAndDisplayFromXmlResource( ".../cloudBalancingBenchmarkConfig.xml");
If you programmatically adjust the benchmark configuration, you can use BenchmarkAggregatorFrame.createAndDisplay(PlannerBenchmarkConfig)
instead.
Removed JavaScript expression support in configuration
Minor
Various elements of both the solver configuration and benchmark configuration no longer support nested JavaScript expressions. You must replace these with either auto-configuration or with integer constants.
An example from the solverConfig.xml
file in OptaPlanner 7:
<solver> ... <moveThreadCount>availableProcessorCount - 1</moveThreadCount> ... </solver>
An example from the`solverConfig.xml`file in OptaPlanner 8:
<solver> ... <moveThreadCount>1</moveThreadCount> <!-- Alternatively, use "AUTO" or omit entirely. --> ... </solver>
An example from the benchmarkConfig.xml
file in OptaPlanner 7:
<plannerBenchmark> ... <parallelBenchmarkCount>availableProcessorCount - 1</parallelBenchmarkCount> ... </plannerBenchmark>
An example from the benchmarkConfig.xml
file in OptaPlanner 8:
<plannerBenchmark> ... <parallelBenchmarkCount>1</parallelBenchmarkCount> <!-- Alternatively, use "AUTO" or omit entirely. --> ... </plannerBenchmark>
Removed the deprecated variable listeners
Major, Public API
The deprecated interface VariableListener
from package org.optaplanner.core.impl.domain.variable.listener
has ben removed, along with the deprecated interface StatefulVariableListener
and the deprecated class VariableListenerAdapter
in that same package. Use an interface VariableListener
from package org.optaplanner.core.api.domain.variable
instead.
An example of a VariableListener.java
file in OptaPlanner 7:
... import org.optaplanner.core.impl.domain.variable.listener.VariableListenerAdapter; ... public class MyVariableListener extends VariableListenerAdapter<Object> { ... @Override void afterEntityRemoved(ScoreDirector scoreDirector, Object entity); ... } ... }
An example from a VariableListener.java
file in OptaPlanner 8:
... import org.optaplanner.core.api.domain.variable.VariableListener; ... public class MyVariableListener extends VariableListener<MySolution, Object> { ... @Override void afterEntityRemoved(ScoreDirector<MySolution> scoreDirector, Object entity); ... } ... }
An example of a StatefulVariableListener.java
file in OptaPlanner 7:
... import org.optaplanner.core.impl.domain.variable.listener.StatefulVariableListener; ... public class MyStatefulVariableListener implements StatefulVariableListener<Object> { ... @Override public void clearWorkingSolution(ScoreDirector scoreDirector) { ... } ... }
An example from the StatefulVariableListener.java
file in OptaPlanner 8:
... import org.optaplanner.core.api.domain.variable.VariableListener; ... public class MyStatefulVariableListener implements VariableListener<MySolution, Object> { ... @Override public void close() { ... } ... }