March 10, 2026
3
min

Solver 2.x: Java Platform Module System (JPMS) support.

Tom Cools
Keep up with Timefold
Product updates, optimization insights, and stories from the builders behind PlanningAI.
Share

We recently announced Timefold Solver 2.x, slated for somewhere later this month. It’s our first real major version since the fork (1.x was largely a package rename from the old OptaPlanner days) which means it’s finally time to address some issues we’ve been wanting to tackle for ages. One of them was modularity.

Java's public challenge

In Java, classes have a few visibility options. private, package-private, protected, and public. Large libraries often end up marking internal classes as public so different packages inside the library can interact. That’s exactly what happened in Timefold over the years.

As the codebase grew, some classes were technically public but never meant to be used by consumers. You’ve probably seen them:

ai.timefold.solver.core.*impl.*

Those packages contain implementation details of the solver. But since the classes were public, they were sometimes used anyway. From a user’s perspective, the reasoning is understandable: "If it’s public, why shouldn’t I use it?"

For years, Java lacked a visibility level that meant “public within this codebase, but not part of the supported API.” That changed with the introduction of Java Platform Module System (JPMS), which we will formally be supporting starting with Solver 2.0.

With JPMS we can explicitly choose which packages are exported and which remain internal.

module ai.timefold.solver.core {

   exports ai.timefold.solver.core.api.domain.common;
   exports ai.timefold.solver.core.api.domain.entity;
   exports ai.timefold.solver.core.api.domain.solution;
   exports ai.timefold.solver.core.api.domain.solution.cloner;
   
   // rest of file excluded
}

Exported packages are the supported API. Everything else stays internal. In other words:

public no longer means “public to the world.”

(If you run everything on the classpath instead of the modulepath, JPMS boundaries can still be bypassed. But for Solver 2.x, exported packages define the supported API.)

Why does this matter?

This change is mostly about clarity and long-term stability.

With explicit API boundaries we can:

  • avoid accidental dependencies on internals
  • refactor internal code more freely
  • make upgrades less risky

Internal classes may change or disappear without notice. Exported packages are the stable API.

If you depend on internal classes

If your code imports packages containing .impl., you’re probably using internals.

Sometimes that happened because certain advanced use cases required it (e.g. Custom Moves). We’re actively working on replacing those patterns with supported public APIs.

If you have a legitimate use case that depends on internals, we’d like to hear about it. The goal isn’t to block anything, it’s to provide stable ways to do what you need without relying on implementation details.

If you’re using Timefold Solver and have concerns about internal classes you depend on, now is a great time to let us know.

Related blogs
June 25, 2026
0
min

Same coffee, same shoes, same plan: the beauty of no surprises

Optimization
Explainable AI
June 23, 2026
0
min

Timefold Raises $13M as AI Drives Demand for Routing and Scheduling APIs

Press
June 1, 2026
0
min

How upskilling technicians unlocks field service routing efficiency

Explainable AI
FSR
Platform
May 4, 2026
0
min

How much fuel can route optimization actually save?

FSR
Scheduling intelligence
Platform
May 1, 2026
0
min

Three optimizations to make your Timefold Solver faster

Solver
Open-source
April 24, 2026
0
min

Timefold Solver 2.0 upgrade: 15 projects, under 10 minutes

Solver
Open-source

When scheduling works, everything works.

Less waste. More control. Teams that trust the plan.