OptaPlanner logo
  • Download
  • Learn
    • Documentation
    • Videos
    • Slides
    • Training

    • Use cases
    • Compatibility
    • Testimonials and case studies
  • Get help
  • Blog
  • Source
  • Team
  • Services
  • KIE
    • Drools
    • OptaPlanner
    • jBPM
    • Kogito
  • Star
  • T
  • L
  • F
  • YT
Fork me on GitHub

Upgrade recipe 6.4

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 8.

Legend

Every upgrade note has an indication how likely your code will be affected by that change:

  • Major Likely to affect your code.
  • Minor Unlikely to affect your code (especially if you followed the examples), unless you have hacks.
  • Impl detail Will not affect your code, unless you have very deep hacks.
  • Recommended Not a backward incompatible change, but you probably want to do this.
  • Readme Read this to better understand why the subsequent major changes were made.

Upgrade from an older version

To upgrade from an older version, first apply the previous upgrade recipes.

Note for Red Hat Decision Manager customers

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)

From 6.3.0.Final to 6.4.0.Beta1

Custom ScoreDefinition: getLevelLabels() added

If you have a custom ScoreDefinition: that interface has new method getLevelLabels(). AbstractScoreDefinition and AbstractFeasibilityScoreDefinition now expect those levelLabels as a constructor parameter.

Before in *.java:

public class HardSoftScoreDefinition extends AbstractFeasibilityScoreDefinition<HardSoftScore> {
    public HardSoftScoreDefinition() {}
    public int getLevelsSize() {
        return 2;
    }
    ...
}

After in *.java:

public class HardSoftScoreDefinition extends AbstractFeasibilityScoreDefinition<HardSoftScore> {
    public HardSoftScoreDefinition() {
        super(new String[]{"hard score", "soft score"});
    }
    ...
}

SolutionFileIO: moved to another jar

If you’re using SolutionFileIO: that class has been moved from the optaplanner-benchmark jar to optaplanner-persistence-common jar.

After in pom.xml:

<dependency>
  <groupId>org.optaplanner</groupId>
  <artifactId>optaplanner-persistence-common</artifactId>
</dependency>

XStreamScoreConverter: moved to another jar

If you’re using XStreamScoreConverter: that class has been moved from the optaplanner-benchmark jar to optaplanner-persistence-xstream jar.

After in pom.xml:

<dependency>
  <groupId>org.optaplanner</groupId>
  <artifactId>optaplanner-persistence-xstream</artifactId>
</dependency>

BendableScore and XStream: XStreamBendableScoreConverter replaced

If you’re using BendableScore and XStream: XStreamBendableScoreConverter (which only supported BendableScore) has been deleted. The generic XStreamScoreConverter now supports BendableScore, BendableLongScore and BendableBigDecimalScore too.

Before in *.java:

@XStreamConverter(value = XStreamBendableScoreConverter.class, ints = {1, 2})
private BendableScore score;

After in *.java:

@XStreamConverter(value = XStreamScoreConverter.class, types = {BendableScoreDefinition.class}, ints = {1, 2})
private BendableScore score;

Custom ScoreDefinition: fromLevelNumbers() added

If you have a custom ScoreDefinition: that interface has another new method fromLevelNumbers(). It does the opposite of Score.toLevelNumbers().

After in *.java:

public class HardSoftScoreDefinition extends AbstractFeasibilityScoreDefinition<HardSoftScore> {
    ...
    @Override
    public HardSoftScore fromLevelNumbers(Number[] levelNumbers) {
        if (levelNumbers.length != getLevelsSize()) {
            throw new IllegalStateException("The levelNumbers (" + Arrays.toString(levelNumbers)
                    + ")'s length (" + levelNumbers.length + ") must equal the levelSize (" + getLevelsSize() + ").");
        }
        return HardSoftScore.valueOf((Integer) levelNumbers[0], (Integer) levelNumbers[1]);
    }
}

JPA-Hibernate with OptaPlanner: use new jar

If you’re using JPA-Hibernate with OptaPlanner, you’ll want to take advantage of the new jar optaplanner-persistence-jpa. See docs chapter "Integration" for more information.

Custom Benchmarker ranking: SingleBenchmarkResult methods renamed

If you’re using SingleBenchmarkResult: the functionality of the method getScore() and getUninitializedVariableCount() has moved to getAverageScore() and getAverageUninitializedVariableCount() because of the addition of SubSingleBenchmarkResult (Statistical benchmarking).

Before in *.java:

singleBenchmarkResult.getScore();
singleBenchmarkResult.getUninitializedVariableCount();

After in *.java:

singleBenchmarkResult.getAverageScore();
singleBenchmarkResult.getAverageUninitializedVariableCount();

Every SingleStatistic class: renamed

If you’re using SingleStatistic or any of its subclasses: all of them were renamed to include "Sub" as a part of Statistical benchmarking. The package org.optaplanner.benchmark.impl.statistic.single was also renamed to org.optaplanner.benchmark.impl.statistic.subsingle. SingleStatisticType has not been changed, therefore no changes in the configuration are needed.

Before in *.java:

import org.optaplanner.benchmark.impl.statistic.bestscore.BestScoreSingleStatistic;
...

    BestScoreSingleStatistic singleStatistic;

After in *.java:

import org.optaplanner.benchmark.impl.statistic.bestscore.BestScoreSubSingleStatistic;
...

    BestScoreSubSingleStatistic subSingleStatistic;

Configure SolverFactory per request: use cloneSolverFactory()

If you’re configuring the SolverFactory dynamically for each user request with differ settings, use SolverFactory.cloneSolverFactory() to avoid a race condition.

TerminationConfig: clone() removed

The method TerminationConfig.clone() has been removed. The inherit() method now guarantees that afterwards changing the child or parent will not affect the other.

Before in *.java:

TerminationConfig clone = terminationConfig.clone();

After in *.java:

TerminationConfig clone = new TerminationConfig();
clone.inherit(terminationConfig);

SwingUtils and SwingUncaughtExceptionHandler: moved

If you’ve copy pasted the examples Swing UI, you might be using SwingUtils and SwingUncaughtExceptionHandler. These classes are now in a different package (in the same jar for now).

Before in *.java:

import org.optaplanner.benchmark.impl.aggregator.swingui.SwingUncaughtExceptionHandler;
import org.optaplanner.benchmark.impl.aggregator.swingui.SwingUtils;

After in *.java:

import org.optaplanner.swing.impl.SwingUncaughtExceptionHandler;
import org.optaplanner.swing.impl.SwingUtils;

TangoColorFactory: moved

The class TangoColorFactory has moved to a different package and from optaplanner-examples into optaplanner-benchmark.

Before in *.java:

import org.optaplanner.examples.common.swingui.TangoColorFactory;

After in *.java:

import org.optaplanner.swing.impl.TangoColorFactory;

SolverFactory and Solver: added optional generic type parameter

To avoid the awkward cast to your Solution implementation, both SolverFactory and Solver now optionally support a generic type parameter.

Before in *.java:

    SolverFactory solverFactory = SolverFactory.createFromXmlResource(
            "org/.../cloudBalancingSolverConfig.xml");
    Solver solver = solverFactory.buildSolver();
    solver.solve(unsolvedCloudBalance);
    CloudBalance solvedCloudBalance = (CloudBalance) solver.getBestSolution();

After in *.java:

    SolverFactory<CloudBalance> solverFactory = SolverFactory.createFromXmlResource(
            "org/.../cloudBalancingSolverConfig.xml");
    Solver<CloudBalance> solver = solverFactory.buildSolver();
    solver.solve(unsolvedCloudBalance);
    CloudBalance solvedCloudBalance = solver.getBestSolution();

The old code still works too, because this is part of the public API which is backwards compatible.

Solver: solve() method returns the best solution

The solve() method now returns the best solution, in which case calling getBestSolution() is no longer needed:

Before in *.java:

    solver.solve(unsolvedCloudBalance);
    CloudBalance solvedCloudBalance = solver.getBestSolution();

After in *.java:

    CloudBalance solvedCloudBalance = solver.solve(unsolvedCloudBalance);

The old code still works too, because this is part of the public API which is backwards compatible.

CustomPhaseCommand: new method applyCustomProperties() added

The CustomPhaseCommand has a new method applyCustomProperties() to allow custom properties to be defined in the solver configuration. Instead of implementing that method, you can also extend the new abstract class AbstractCustomPhaseCommand which implements CustomPhaseCommand and implements that method to do nothing (except a validation check).

Before in *.java:

public class ToOriginalMachineSolutionInitializer implements CustomPhaseCommand {
    ...
}

After in *.java:

public class ToOriginalMachineSolutionInitializer extends AbstractCustomPhaseCommand {
    ...
}

[.upgrade-recipe-readme] KieContainer and kjar support for Solver

OptaPlanner now supports kjars, to consume a kjar produced by OptaPlanner Workbench or to deploy a kjar to OptaPlanner Execution Server.

If you need to load a solver configuration or score rules that change more often than your application is released, take a look at the reference manual and SolverFactory.createFromKieContainerXmlResource(…​).

From 6.4.0.Beta1 to 6.4.0.CR1

Thread interruption is now detected

If the thread that called Solver.solve(…​) is interrupted, the solver now terminates early. This ensures a graceful shutdown of each solver when shutdownNow() is called on an ExecutorService of solvers.

Latest release
  • 8.23.0.Final released
    Thu 23 June 2022
Upcoming events
    Add event / Archive
Latest blog posts
  • Run OptaPlanner workloads on OpenShift, part I.
    Thu 9 June 2022
    Radovan Synek
  • OptaPlanner deprecates score DRL
    Thu 26 May 2022
    Lukáš Petrovický
  • Real-time planning meets SolverManager
    Mon 7 March 2022
    Radovan Synek
  • OptaPlanner documentation turns over a new leaf
    Tue 26 October 2021
    Radovan Synek
  • Order picking optimization in warehouses and supermarkets with OptaPlanner
    Thu 14 October 2021
    Walter Medvedeo
  • Monitor OptaPlanner solvers through Micrometer
    Tue 12 October 2021
    Christopher Chianelli
  • A new AI constraint solver for Python: OptaPy
    Tue 5 October 2021
    Christopher Chianelli
  • Blog archive
Latest videos
  • Host your OptaPlanner app on OpenShift (Kubernetes)
    Mon 7 February 2022
    Geoffrey De Smet
  • OptaPlanner - A fast, easy-to-use, open source AI constraint solver for software developers
    Mon 31 January 2022
  • Order picking planning with OptaPlanner
    Fri 31 December 2021
    Anna Dupliak
  • AI lesson scheduling on Quarkus with OptaPlanner
    Thu 18 November 2021
    Geoffrey De Smet
  • Maintenance scheduling
    Fri 12 November 2021
    Geoffrey De Smet
  • Optimized order picking in warehouses and supermarkets
    Tue 26 October 2021
    Walter Medvedeo
  • A modern OO/FP constraint solver
    Tue 14 September 2021
    Geoffrey De Smet
  • Video archive

OptaPlanner is open. All dependencies of this project are available under the Apache Software License 2.0 or a compatible license. OptaPlanner is trademarked.

This website was built with JBake and is open source.

Community

  • Blog
  • Get Help
  • Team
  • Governance
  • Academic research

Code

  • Build from source
  • Issue tracker
  • Release notes
  • Upgrade recipes
  • Logo and branding

KIE projects

  • Drools rule engine
  • OptaPlanner constraint solver
  • jBPM workflow engine
  • Kogito Business Automation platform
CC by 3.0 | Privacy Policy
Sponsored by Red Hat