Toggle navigation OptaPlanner logo
  • Home
  • Download
  • Learn
    • Documentation
    • Videos
    • Slides
    • Training
    • Use cases
    • Compatibility
    • Testimonials and case studies
  • Get help
  • Source
  • Team
  • Services
  • Star
  • @OptaPlanner
  • Fb
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 6.4.

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.7 7.33
7.8 7.39
7.9 7.44

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 it’s 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.

Comments

Visit our forum to comment
Latest release
  • 8.5.0.Final released
    Thu 15 April 2021
Paid support and consulting

Want to talk to the experts? Red Hat offers certified binaries with enterprise consulting. Contact optaplanner-info for more information.

Upcoming events
  • SouJava MOTU
    Worldwide - Thu 15 April 2021
    • Planejamento de Recursos com OptaPlanner by Karina Varela, Otávio Santana
Add event / Archive
Latest blog posts
  • Batch solving an ActiveMQ queue that contains planning problem data sets in a scalable way
    Thu 25 March 2021
     Radovan Synek
  • Optimizing COVID-19 vaccination appointment scheduling
    Thu 4 March 2021
     Paul Brown
  • How much faster is Java 15?
    Tue 26 January 2021
     Michal Tomčo
  • Solve the facility location problem
    Fri 9 October 2020
     Jiří Locker
  • OptaPlanner Week 2020 recordings
    Mon 7 September 2020
     Geoffrey De Smet
  • Let’s OptaPlan your jBPM tasks (part 1) - Integrating the two worlds
    Fri 3 July 2020
     Walter Medvedeo
  • AI versus Covid-19: How Java helps nurses and doctors in this fight
    Fri 8 May 2020
     Christopher Chianelli
Blog archive
Latest videos
  • YT Unit testing constraints
    Tue 9 March 2021
     Lukáš Petrovický
  • YT Maintenance scheduling
    Wed 24 February 2021
     Julian Cui
  • YT Vaccination appointment scheduling
    Wed 3 February 2021
     Geoffrey De Smet
  • YT Shadow variables
    Tue 19 January 2021
     Geoffrey De Smet
  • YT Domain modeling and design patterns
    Tue 17 November 2020
     Geoffrey De Smet
  • YT Quarkus insights: AI constraint solving
    Tue 20 October 2020
     Geoffrey De Smet
  • YT AI in kotlin
    Wed 23 September 2020
     Geoffrey De Smet
Video archive

KIE projects

  • Drools rule engine
  • OptaPlanner constraint solver
  • jBPM workflow engine

Community

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

Code

  • Build from source
  • Submit a bug
  • License (Apache-2.0)
  • Release notes
  • Upgrade recipes
Sponsored by
Red Hat
More coder content at
Red Hat Developers
© Copyright 2006-2021, Red Hat, Inc. or third-party contributors - Privacy statement - Terms of use - Website info