Release Notes

This chapter lists new and noteworthy updates in OptaPlanner releases. OptaPlanner follows a 3-week release cycle. Bug fixes and minor improvements are generally not announced, which is why some of the minor releases are not mentioned here.

For a step-by-step migration guide, see our upgrade recipe. We even provide a migration tool to make many of these changes automatically.

For release notes on OptaPlanner 7.x and older, please visit Release Notes on

OptaPlanner 8.x Release Notes

OptaPlanner 8.37.0.Final

PlanningListVariable supports nearby selection

Nearby selection is now available for planning domains using a planning list variable.

AbstractScoreHibernateType and its subtypes become deprecated

The AbstractScoreHibernateType as well as all its subtypes have been deprecated. The parallel OptaPlanner 9 releases are going to introduce Hibernate 6, which unfortunately breaks backward compatibility of the CompositeUserType that the AbstractScoreHibernateType depends on.

The AbstractScoreHibernateType and its subtypes remain available in the OptaPlanner 8 releases to provide integration with Hibernate 5 but have been removed from the equivalent OptaPlanner 9.x release.

To integrate the PlanningScore of your choice with Hibernate 6, either use the score converters available in the org.optaplanner.persistence.jpa.api.score.buildin package or implement the CompositeUserType yourself.

OptaPlanner 8.36.0.Final

OptaWeb Vehicle Routing demo application abandoned

The codebase for OptaWeb Vehicle Routing demo application has been frozen and will no longer receive any updates.

We encourage users to check out the OptaPlanner Vehicle Routing Quickstart for a simple and straight-forward way of integrating OptaPlanner in your application.

OptaPlanner 8.35.0.Final

PlanningListVariable gets support for K-Opt Moves

A new move selector for list variables, KOptListMoveSelector, has been added. The KOptListMoveSelector selects a single entity, removes k edges from its route, and add k new edges from the removed edges' endpoints. The KOptListMoveSelector can help the solver escape local optima in vehicle routing problems. Configuration options are available in the documentation.

SolutionManager gets support for updating shadow variables

SolutionManager (formerly ScoreManager) methods such as explain(solution) and update(solution) received a new overload with an extra argument, SolutionUpdatePolicy. This has often been requested by users who load their solutions from persistent storage (such as a relational database), where these solutions do not include the information carried by shadow variables or even the score. By calling these new overloads and picking the right policy, OptaPlanner will automatically compute values for all the shadow variables in the given solution and/or recalculate the score.

Similarly, ProblemChangeDirector received a new method called `updateShadowVariables(), so that you can update shadow variables on demand in real-time planning.

OptaPlanner 8.34.0.Final

Performance improvements in pillar moves and nearby selection

OptaPlanner can now auto-detect situations where multiple pillar move selectors can share a pre-computed pillar cache and reuse it instead of recomputing it for each move selector. Users who combine different pillar moves (such as PillarChangeMove and PillarSwapMove) should see significant benefits.

The same applies to users of nearby selection. OptaPlanner can now auto-detect situations where a pre-computed distance matrix can be shared between multiple move selectors, saving a considerable amount of memory and CPU processing time.

As a consequence, implementations of the following interfaces are expected to be stateless:

  • org.optaplanner.core.impl.heuristic.selector.common.nearby.NearbyDistanceMeter

  • org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionFilter

  • org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionProbabilityWeightFactory

  • org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorter

  • org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory

In general, if solver configuration asks the user to implement an interface, the expectation is that the implementation will be stateless or at the very least not try to include external state. With the aforementioned performance improvements, failing to follow this requirement will result in subtle bugs and score corruption as the solver will now reuse these instances as it sees fit.

OptaPlanner configuration becomes even more fluent

Various configuration classes, such as EntitySelectorConfig and ValueSelectorConfig, received new builder methods which make it easier than ever to replace XML-based solver config with fluent Java code.

OptaPlanner 8.33.0.Final

Value range auto-detection

In most cases, links between planning variables and value ranges can now be auto-detected. Therefore, @ValueRangeProvider no longer needs to provide an id property. Likewise, planning variables no longer need to reference value range providers via valueRangeProviderRefs property.

No code changes or configuration changes are required. Users who prefer clarity over brevity may continue to explicitly reference their value range providers.

OptaPlanner 8.32.0.Final

XStream support deprecated

Given that XStream has multiple CVEs against it and no recent releases, we have decided to deprecate OptaPlanner’s support for serializing into XML using XStream. To continue serializing into XML, please switch to the optaplanner-persistence-jaxb module.

All classes in the optaplanner-persistence-xstream, as well as the module itself, are now deprecated and will be removed in a future major version of OptaPlanner.

All examples in the optaplanner-examples module have been refactored to JSON using the optaplanner-persistance-jackson module. Quickstarts were not affected by these changes, as they already were serializing into JSON.

OptaPlanner 8.31.0.Final

Several OptaPlanner examples removed from the distribution

In an ongoing effort to clean up code and reduce technical debt, the following examples were removed the optaplanner-examples module:

  • Batch Scheduling,

  • Cheap Time,

  • Coach Shuttle Gathering,

  • Investment

  • and Rock Tour.

We believe these examples were rarely used if ever, and they did not showcase any unique feature of OptaPlanner that would not be showcased already in any of the 16 remaining examples and many quickstarts.

No OptaPlanner feature was removed or deprecated in the process.

Multiple entity classes with chained planning variables

Fixed a bug that prevented using two or more chained planning variables, each defined on a different planning entity class.

OptaPlanner 8.30.0.Final

OptaPlanner operator (experimental) is available in the distribution

While the OptaPlanner operator remains experimental, it has now become a part of the OptaPlanner distribution.

If you want to learn more about the operator, follow the Kubernetes demo.

OptaPlanner 8.29.0.Final

Custom justifications and indictments in Constraint Streams

With a new Constraint Streams API, it is now easy to define custom constraint justifications and indictments in your constraints:

    protected Constraint vehicleCapacity(ConstraintFactory factory) {
        return factory.forEach(Customer.class)
                .filter(customer -> customer.getVehicle() != null)
                .groupBy(Customer::getVehicle, sum(Customer::getDemand))
                .filter((vehicle, demand) -> demand > vehicle.getCapacity())
                        (vehicle, demand) -> demand - vehicle.getCapacity())
                .justifyWith((vehicle, demand, score) ->
                    new VehicleDemandOveruse(vehicle, demand, score))
                .indictWith((vehicle, demand) -> List.of(vehicle))

Note the new methods: justifyWith(…​) and indictWith(…​). To find out more, see customizing justifications and indictments.

Compatible with JDK 19

OpenJDK 19 was recently released and OptaPlanner is fully compatible with it.

We always test our releases against the long-term supported versions of the JDK, currently 11 and 17, as well as against the latest release. We encourage you to upgrade your JDK regularly to benefit from the enhancements that come with the new releases.

New @ShadowVariable and @PiggybackShadowVariable annotations replace the @CustomShadowVariable

@ShadowVariable annotation is repeatable and allows to specify 1 listener per source variable.

@PiggybackShadowVariable is a specialized annotation to mark shadow variables that are updated by another shadow variable’s listener.

The @CustomShadowVariable has been deprecated.

Read more about custom shadow variables in the documentation.

Planning list variable

OptaPlanner now adds a limited support for planning list variables that can hold multiple planning values. The planning list variable provides an alternative approach to modeling planning problems that were previously modeled using the chained planning variable.

Both the planning list variable and the chained planning variable should be used with problems where the goal is to distribute a number of workload elements among limited resources in a specific order. For example, in vehicle routing, vehicles represent the limited resource and customers represent the workload elements.

The chained planning variable defines a recursive data structure, in which customers form chains ending with vehicles. On the other hand, the planning list variable allows for a more intuitive model where each vehicle holds a list of customers it goes to. It is defined using the new @PlaningListVariable annotation.

The planning list variable is a new feature and lacks some advanced features, that are available with the chained planning variable.

OptaPlanner 8.27.0.Final

Bavet is feature complete

The alternative constraint streams implementation Bavet is feature complete. You can now use it as an alternative to Drools (which is still the default).

Bavet will not be supported in Red Hat’s support offering. Drools intends to catch up performance wise.

OptaPlanner 8.24.0.Final

OptaWeb Employee Rostering demo application abandoned

The codebase for OptaWeb Employee Rostering demo application has been frozen and will no longer receive any updates.

We encourage users to check out the OptaPlanner Employee Rostering Quickstart for a simple and straight-forward way of integrating OptaPlanner in your application.

OptaPlanner 8.23.0.Final

Score DRL deprecated in favor of Constraint Streams

Support for Score DRL has been deprecated and users are encouraged to migrate to Constraint Streams at their earliest convenience. Read the migration guide from score DRL to Constraint Streams. Score DRL is not going away in OptaPlanner 8.

OptaPlanner 8.20.0.Final

SolverManager.addProblemChange() now returns CompletableFuture<Void>

SolverManager.addProblemChange() returns CompletableFuture<Void>, which completes when a new best solution containing the problem change has been passed to a user-defined Consumer.

OptaPlanner 8.17.0.Final

Real-time planning available on the SolverManager

The SolverManager now accepts problem changes via the addProblemChange() method, allowing for real-time planning without much boilerplate code.

Faster Solver creation

SolverFactory newly caches some internal data structures, leading to much faster Solver creation times. This is beneficial if you instantiate multiple Solver instances in quick succession.

OptaPlanner 8.12.0.Final

Documentation website

The latest final OptaPlanner documentation is now available on a new documentation website built using Antora. The single-HTML and PDF documentation will continue to be published in the archive.

Monitoring Support

OptaPlanner now uses Micrometer to monitor key metrics such as active solver count, solve durations, and error count.

OptaPlanner 8.10.0.Final

Support for Quarkus 2.0

OptaPlanner is now fully compatible with the recently released Quarkus 2.0.

OptaPlanner 8.7.0.Final

OptaPlanner quickstarts repository

There is a new quarkus-call-center quickstart that shows real-time planning of incoming calls in a call center.

Quarkus Call Center

OptaPlanner 8.5.0.Final

Mapping in Constraint Streams

The Constraint Streams API received a major new functionality. You can now modify your streams using mapping functions.

Ready for OpenJDK 16

We have made some tweaks under the hood so that your experience with the recently released OpenJDK 16 continues to be smooth.

Inject and Autowire ConstraintVerifier in Quarkus and Spring Boot

OptaWebs on Quarkus

OptaWeb Vehicle Routing and OptaWeb Employee Rostering have been migrated from Spring Boot to Quarkus.

Other noteworthy changes done during the migration to Quarkus:

  • OptaWeb Vehicle Routing back end has a new RESTful API. Client-server communication, that was previously done using WebSockets, now uses a combination of REST calls and Server-Sent Events.

  • OptaWeb Employee Rostering now uses Constraint Streams instead of DRL for score calculation.

Faster domain accessors and cloning with Gizmo

We have added Gizmo generated domain accessors and solution cloners, which offer better performance than the reflection based domain accessors and solution cloners.

OptaPlanner quickstarts repository

There is a new activemq-quarkus-school-timetabling quickstart that shows how to integrate ActiveMQ with OptaPlanner to horizontally scale when solving multiple data sets.

OptaPlanner 8.3.0.Final

Major performance improvements for Constraint Streams

The default implementation of the Constraint Streams API has seen major performance improvements. Use cases with tri and quad streams may experience order of magnitude speedups. Use cases with grouping are likely to experience some speedups too, albeit comparatively smaller.

Kudos to the Drools team for helping make this possible!

Constraint Streams groupBy() overloads for multiple collectors

The Constraint Streams API has been extended to allow using more than 2 collectors in a single grouping. The following is now possible:

return constraintFactory.from(ProductPrice.class)
    .groupBy(min(), max(), sum())
    .penalize(..., SimpleScore.ONE, (minPrice, maxPrice, sumPrices) -> ...);

OptaPlanner 8.0.0.Final

OptaPlanner quickstarts repository

The new OptaPlanner Quickstarts repository contains pretty web demos for several use cases. It also shows you how to integrate OptaPlanner with different technologies:

  • School timetabling: Assign lessons to timeslots and rooms to produce a better schedule for teachers and students.

    This application connects to a relational database and exposes a REST API, rendered by a pretty JavaScript UI.

    • quarkus-school-timetabling: Java, Maven or Gradle, Quarkus, H2

    • spring-boot-school-timetabling: Java, Maven or Gradle, Spring Boot, H2

    • kotlin-quarkus-school-timetabling: Kotlin, Maven, Quarkus, H2

  • Facility location problem (FLP): Pick the best geographical locations for new stores, distribution centers, COVID-19 test centers or telco masts.

    • quarkus-facility-location: Java, Maven, Quarkus

  • Factorio layout: Assign machines to assembly line locations to design the best factory layout.

    • quarkus-factorio-layout: Java, Maven, Quarkus

  • Maintenance scheduling: Coming soon

Future Java compatibility

The OptaPlanner 8 API has been groomed to maximize compatibility with the latest OpenJDK and GraalVM releases and game-changing platforms such as Quarkus. Meanwhile, we still fully support OpenJDK 11 and platforms such as Spring Boot or plain Java.

For example, when running OptaPlanner in Java 11 or higher with a classpath, OptaPlanner no longer triggers WARNING: An illegal reflective access operation has occurred for XStream.

Code completion for solverConfig.xml and benchmarkConfig.xml through XSD

To validate XML configuration during development, add the new XML Schema Definition (XSD) on the solver or benchmark configuration:

<?xml version="1.0" encoding="UTF-8"?>
<solver xmlns="" xmlns:xsi="" xsi:schemaLocation="">

This enables code completion for XML in most IDEs:


Improved Quarkus extension

The OptaPlanner Quarkus extension is now stable and displays no warnings when compiling Java to a native executable.

ScoreManager now supports score explanation

The ScoreManager can now also explain why a solution has a certain score:

ScoreManager<TimeTable, HardSoftScore> scoreManager = ScoreManager.create(solverFactory);
ScoreExplanation<TimeTable, HardSoftScore> scoreExplanation = scoreManager.explain(timeTable);

Additionally, use scoreExplanation.getConstraintMatchTotalMap() and scoreExplanation.getIndictmentMap() to extract the ConstraintMatchTotal<HardSoftScore> and Indictment<HardSoftScore> information without triggering a new score calculation.

Various improvements

  • The ConstraintStreams API is now richer, more stable with better error messages and faster.

  • The SolverManager API now supports to listen to both best solution events and the solving ended event.

  • OptaPlanner no longer depends on Guava or Reflections.