diff --git a/build/build-parent/pom.xml b/build/build-parent/pom.xml
index ef9086225db..3d8b1f10d81 100644
--- a/build/build-parent/pom.xml
+++ b/build/build-parent/pom.xml
@@ -454,6 +454,28 @@
-Xlint:none
+
+
+ default-compile
+ compile
+
+ compile
+
+
+
+
+
+
+ default-testCompile
+ test-compile
+
+ testCompile
+
+
+ false
+
+
+
org.jacoco
@@ -568,6 +590,8 @@
maven-surefire-plugin
${version.surefire.plugin}
+
+ false
true
@@ -575,6 +599,8 @@
maven-failsafe-plugin
${version.surefire.plugin}
+
+ false
true
diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java
new file mode 100644
index 00000000000..9be51ef0fd6
--- /dev/null
+++ b/core/src/main/java/module-info.java
@@ -0,0 +1,202 @@
+module ai.timefold.solver.core {
+ // explicit exports to other modules
+ exports ai.timefold.solver.core.impl.solver.scope to
+ ai.timefold.solver.jackson, ai.timefold.solver.benchmark, ai.timefold.solver.spring.boot.autoconfigure,
+ ai.timefold.solver.quarkus.deployment, ai.timefold.solver.quarkus.integration.test,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.constructionheuristic.event to
+ ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.constructionheuristic.scope to
+ ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.io.jaxb to
+ ai.timefold.solver.jackson, ai.timefold.solver.jaxb, ai.timefold.solver.spring.boot.autoconfigure,
+ ai.timefold.solver.benchmark,
+ ai.timefold.solver.quarkus,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.entity.descriptor
+ to ai.timefold.solver.jackson, ai.timefold.solver.jaxb, ai.timefold.solver.benchmark,
+ ai.timefold.solver.spring.boot.autoconfigure, ai.timefold.solver.quarkus.integration.test,
+ ai.timefold.solver.quarkus,
+ ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.solution to ai.timefold.solver.jackson, ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.variable.descriptor
+ to ai.timefold.solver.jackson, ai.timefold.solver.jaxb, ai.timefold.solver.benchmark,
+ ai.timefold.solver.quarkus, ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.util
+ to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.quarkus.deployment, ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.stream to ai.timefold.solver.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.stream.collector
+ to ai.timefold.solver.jackson, ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.solver
+ to ai.timefold.solver.jackson, ai.timefold.solver.spring.boot.autoconfigure, ai.timefold.solver.benchmark,
+ ai.timefold.solver.quarkus,
+ ai.timefold.solver.quarkus.deployment, ai.timefold.solver.quarkus.integration.test,
+ ai.timefold.solver.quarkus.jackson,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.io.jaxb.adapter to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.definition
+ to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.entity to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.entity.pillar
+ to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.move to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.value to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.localsearch.event to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.phase.event to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.phase.scope to ai.timefold.solver.jackson, ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.common.nearby
+ to ai.timefold.solver.jackson,
+ ai.timefold.solver.benchmark,
+ ai.timefold.solver.benchmark.aggregator,
+ ai.timefold.solver.spring.boot.autoconfigure, ai.timefold.solver.quarkus.deployment,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.constraint to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.partitionedsearch.partitioner to ai.timefold.solver.quarkus.deployment,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.common.decorator to ai.timefold.solver.quarkus.deployment,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.trend to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.director;
+ exports ai.timefold.solver.core.impl.score.director.easy to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.score.director.incremental to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.solver.monitoring to ai.timefold.solver.benchmark,
+ ai.timefold.solver.enterprise.core;
+
+ // Preview APIs
+ exports ai.timefold.solver.core.preview.api.move;
+ exports ai.timefold.solver.core.preview.api.move.builtin;
+ exports ai.timefold.solver.core.preview.api.domain.metamodel;
+ exports ai.timefold.solver.core.preview.api.domain.solution.diff;
+ exports ai.timefold.solver.core.api.score.stream.test;
+
+ // enterprise specific exports
+ exports ai.timefold.solver.core.impl.bavet.common to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.constructionheuristic.decider to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.constructionheuristic.decider.forager to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.variable to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.variable.supply to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.domain.variable.listener.support to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.common to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.common.iterator to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.entity.mimic to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.list.mimic to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.heuristic.selector.value.mimic to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.localsearch.decider to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.localsearch.decider.acceptor to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.localsearch.decider.forager to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.move to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.neighborhood to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.partitionedsearch to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.phase to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.solver.recaller to ai.timefold.solver.enterprise.core;
+ exports ai.timefold.solver.core.impl.solver.event to ai.timefold.solver.enterprise.core;
+
+ // Broad impl usage
+ exports ai.timefold.solver.core.impl.solver.thread;
+ exports ai.timefold.solver.core.impl.heuristic.move;
+ exports ai.timefold.solver.core.impl.localsearch.scope;
+ exports ai.timefold.solver.core.impl.heuristic.selector.list;
+ exports ai.timefold.solver.core.impl.heuristic.selector.move.factory;
+ exports ai.timefold.solver.core.impl.heuristic.selector.move.generic;
+ exports ai.timefold.solver.core.impl.heuristic.selector.move.generic.list;
+ exports ai.timefold.solver.core.impl.score.stream.common;
+ exports ai.timefold.solver.core.impl.score.stream.common.inliner;
+ exports ai.timefold.solver.core.impl.score.director.stream;
+ exports ai.timefold.solver.core.impl.score.stream.bavet;
+ exports ai.timefold.solver.core.impl.domain.solution.cloner.gizmo;
+ exports ai.timefold.solver.core.impl.domain.solution.descriptor;
+ exports ai.timefold.solver.core.impl.domain.common.accessor;
+ exports ai.timefold.solver.core.impl.domain.common;
+ exports ai.timefold.solver.core.impl.domain.common.accessor.gizmo;
+ exports ai.timefold.solver.core.impl.solver.termination;
+ exports ai.timefold.solver.core.impl.domain.variable.declarative;
+ exports ai.timefold.solver.core.impl.score.stream.test;
+
+ // expected exports
+ 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;
+ exports ai.timefold.solver.core.api.domain.valuerange;
+ exports ai.timefold.solver.core.api.domain.variable;
+ exports ai.timefold.solver.core.api.function;
+ exports ai.timefold.solver.core.api.score;
+ exports ai.timefold.solver.core.api.score.analysis;
+ exports ai.timefold.solver.core.api.score.stream;
+ exports ai.timefold.solver.core.api.score.stream.common;
+ exports ai.timefold.solver.core.api.score.stream.uni;
+ exports ai.timefold.solver.core.api.score.stream.bi;
+ exports ai.timefold.solver.core.api.score.stream.tri;
+ exports ai.timefold.solver.core.api.score.stream.penta;
+ exports ai.timefold.solver.core.api.score.stream.quad;
+ exports ai.timefold.solver.core.api.score.calculator;
+ exports ai.timefold.solver.core.config.solver;
+ exports ai.timefold.solver.core.config.solver.random;
+ exports ai.timefold.solver.core.config.solver.monitoring;
+ exports ai.timefold.solver.core.config.solver.termination;
+ exports ai.timefold.solver.core.config.heuristic.selector.entity;
+ exports ai.timefold.solver.core.config.heuristic.selector.entity.pillar;
+ exports ai.timefold.solver.core.config.heuristic.selector.list;
+ exports ai.timefold.solver.core.config.heuristic.selector.move;
+ exports ai.timefold.solver.core.config.heuristic.selector.move.factory;
+ exports ai.timefold.solver.core.config.heuristic.selector.move.composite;
+ exports ai.timefold.solver.core.config.heuristic.selector.move.generic;
+ exports ai.timefold.solver.core.config.heuristic.selector.move.generic.list;
+ exports ai.timefold.solver.core.config.heuristic.selector.value;
+ exports ai.timefold.solver.core.config.heuristic.selector.common;
+ exports ai.timefold.solver.core.config.heuristic.selector.common.decorator;
+ exports ai.timefold.solver.core.config.heuristic.selector.common.nearby;
+ exports ai.timefold.solver.core.config.localsearch;
+ exports ai.timefold.solver.core.config.localsearch.decider.forager;
+ exports ai.timefold.solver.core.config.localsearch.decider.acceptor;
+ exports ai.timefold.solver.core.config.localsearch.decider.acceptor.stepcountinghillclimbing;
+ exports ai.timefold.solver.core.config.partitionedsearch;
+ exports ai.timefold.solver.core.config.phase;
+ exports ai.timefold.solver.core.config.phase.custom;
+ exports ai.timefold.solver.core.config.score.director;
+ exports ai.timefold.solver.core.config.score.trend;
+ exports ai.timefold.solver.core.config.util;
+ exports ai.timefold.solver.core.config;
+ exports ai.timefold.solver.core.api.score.constraint;
+ exports ai.timefold.solver.core.api.solver;
+ exports ai.timefold.solver.core.api.solver.event;
+ exports ai.timefold.solver.core.api.solver.phase;
+ exports ai.timefold.solver.core.api.solver.change;
+ exports ai.timefold.solver.core.config.constructionheuristic;
+ exports ai.timefold.solver.core.enterprise;
+
+ requires commons.math3;
+ requires jakarta.xml.bind;
+ requires java.xml;
+ requires micrometer.core;
+ requires org.jspecify;
+ requires org.slf4j;
+ requires io.quarkus.gizmo2;
+}
\ No newline at end of file
diff --git a/persistence/common/src/main/java/module-info.java b/persistence/common/src/main/java/module-info.java
new file mode 100644
index 00000000000..e0c2f4b613a
--- /dev/null
+++ b/persistence/common/src/main/java/module-info.java
@@ -0,0 +1,5 @@
+module ai.timefold.solver.persistence.common {
+ requires ai.timefold.solver.core;
+
+ exports ai.timefold.solver.persistence.common.api.domain.solution;
+}
\ No newline at end of file
diff --git a/persistence/jackson/src/main/java/module-info.java b/persistence/jackson/src/main/java/module-info.java
new file mode 100644
index 00000000000..50c217e3771
--- /dev/null
+++ b/persistence/jackson/src/main/java/module-info.java
@@ -0,0 +1,13 @@
+module ai.timefold.solver.jackson {
+ exports ai.timefold.solver.jackson.api;
+
+ provides tools.jackson.databind.JacksonModule with
+ ai.timefold.solver.jackson.api.TimefoldJacksonModule;
+
+ requires ai.timefold.solver.core;
+ requires ai.timefold.solver.persistence.common;
+ requires org.jspecify;
+ requires tools.jackson.databind;
+
+ uses tools.jackson.databind.JacksonModule;
+}
\ No newline at end of file
diff --git a/persistence/jaxb/src/main/java/module-info.java b/persistence/jaxb/src/main/java/module-info.java
new file mode 100644
index 00000000000..673b4e2001b
--- /dev/null
+++ b/persistence/jaxb/src/main/java/module-info.java
@@ -0,0 +1,8 @@
+module ai.timefold.solver.jaxb {
+ exports ai.timefold.solver.jaxb.api.score;
+
+ requires ai.timefold.solver.persistence.common;
+ requires ai.timefold.solver.core;
+ requires jakarta.xml.bind;
+
+}
\ No newline at end of file
diff --git a/persistence/jpa/src/main/java/module-info.java b/persistence/jpa/src/main/java/module-info.java
new file mode 100644
index 00000000000..dace4a9b621
--- /dev/null
+++ b/persistence/jpa/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module ai.timefold.solver.jpa {
+ requires jakarta.persistence;
+ requires ai.timefold.solver.core;
+
+ exports ai.timefold.solver.jpa.api.score;
+}
\ No newline at end of file
diff --git a/quarkus-integration/pom.xml b/quarkus-integration/pom.xml
index 91eec00eeec..31194accda2 100644
--- a/quarkus-integration/pom.xml
+++ b/quarkus-integration/pom.xml
@@ -40,6 +40,7 @@
maven-surefire-plugin
+ false
org.jboss.logmanager.LogManager
@@ -48,6 +49,7 @@
maven-failsafe-plugin
+ false
org.jboss.logmanager.LogManager
diff --git a/quarkus-integration/quarkus-jackson/deployment/src/main/java/module-info.java b/quarkus-integration/quarkus-jackson/deployment/src/main/java/module-info.java
new file mode 100644
index 00000000000..ed0cae68dd9
--- /dev/null
+++ b/quarkus-integration/quarkus-jackson/deployment/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module ai.timefold.solver.quarkus.jackson.deployment {
+ requires quarkus.core.deployment;
+ requires quarkus.jackson.spi;
+ requires ai.timefold.solver.quarkus.jackson;
+ requires quarkus.core;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus-jackson/integration-test/src/main/java/module-info.java b/quarkus-integration/quarkus-jackson/integration-test/src/main/java/module-info.java
new file mode 100644
index 00000000000..90b8883a924
--- /dev/null
+++ b/quarkus-integration/quarkus-jackson/integration-test/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module ai.timefold.solver.quarkus.jackson.integration.test {
+ requires ai.timefold.solver.core;
+ requires jakarta.inject;
+ requires jakarta.ws.rs;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus-jackson/runtime/src/main/java/module-info.java b/quarkus-integration/quarkus-jackson/runtime/src/main/java/module-info.java
new file mode 100644
index 00000000000..9f35864b240
--- /dev/null
+++ b/quarkus-integration/quarkus-jackson/runtime/src/main/java/module-info.java
@@ -0,0 +1,8 @@
+module ai.timefold.solver.quarkus.jackson {
+ exports ai.timefold.solver.quarkus.jackson;
+
+ requires ai.timefold.solver.core;
+ requires ai.timefold.solver.persistence.common;
+ requires com.fasterxml.jackson.databind;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus/deployment/src/main/java/module-info.java b/quarkus-integration/quarkus/deployment/src/main/java/module-info.java
new file mode 100644
index 00000000000..dac5e5ce099
--- /dev/null
+++ b/quarkus-integration/quarkus/deployment/src/main/java/module-info.java
@@ -0,0 +1,24 @@
+module ai.timefold.solver.quarkus.deployment {
+ requires ai.timefold.solver.quarkus;
+ requires quarkus.arc.deployment;
+ requires quarkus.builder;
+ requires quarkus.core.deployment;
+ requires quarkus.devui.deployment.spi;
+ requires ai.timefold.solver.core;
+ requires io.quarkus.gizmo2;
+ requires jakarta.cdi;
+ requires quarkus.core;
+ requires arc.processor;
+ requires org.jspecify;
+ requires io.quarkus.gizmo;
+ requires org.jboss.jandex;
+ requires io.smallrye.config;
+ requires org.eclipse.microprofile.config;
+ requires org.objectweb.asm;
+ requires org.jboss.logging;
+
+ // Enterprise exports
+ exports ai.timefold.solver.quarkus.deployment to ai.timefold.solver.enterprise.quarkus.deployment;
+ exports ai.timefold.solver.quarkus.deployment.config to ai.timefold.solver.enterprise.quarkus.deployment;
+ exports ai.timefold.solver.quarkus.deployment.api to ai.timefold.solver.enterprise.quarkus.deployment;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus/devui-integration-test/src/main/java/module-info.java b/quarkus-integration/quarkus/devui-integration-test/src/main/java/module-info.java
new file mode 100644
index 00000000000..49e9c0433a2
--- /dev/null
+++ b/quarkus-integration/quarkus/devui-integration-test/src/main/java/module-info.java
@@ -0,0 +1,4 @@
+module ai.timefold.solver.quarkus.devui.integration.test {
+ requires ai.timefold.solver.core;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus/integration-test/src/main/java/module-info.java b/quarkus-integration/quarkus/integration-test/src/main/java/module-info.java
new file mode 100644
index 00000000000..a123ebdef78
--- /dev/null
+++ b/quarkus-integration/quarkus/integration-test/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module ai.timefold.solver.quarkus.integration.test {
+ requires ai.timefold.solver.core;
+ requires jakarta.inject;
+ requires jakarta.ws.rs;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus/pom.xml b/quarkus-integration/quarkus/pom.xml
index 8d18f218942..c6ee15931fc 100644
--- a/quarkus-integration/quarkus/pom.xml
+++ b/quarkus-integration/quarkus/pom.xml
@@ -22,4 +22,22 @@
reflection-integration-test
devui-integration-test
+
+
+
+
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+ 3.1.1-RC1
+ compile
+
+
+
+
+
+ org.eclipse.microprofile.config
+ microprofile-config-api
+
+
diff --git a/quarkus-integration/quarkus/reflection-integration-test/src/main/java/module-info.java b/quarkus-integration/quarkus/reflection-integration-test/src/main/java/module-info.java
new file mode 100644
index 00000000000..61acd4909bf
--- /dev/null
+++ b/quarkus-integration/quarkus/reflection-integration-test/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module ai.timefold.solver.quarkus.reflection.integration.test {
+ requires ai.timefold.solver.core;
+ requires jakarta.inject;
+ requires jakarta.ws.rs;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/quarkus-integration/quarkus/runtime/src/main/java/module-info.java b/quarkus-integration/quarkus/runtime/src/main/java/module-info.java
new file mode 100644
index 00000000000..999d2ef794c
--- /dev/null
+++ b/quarkus-integration/quarkus/runtime/src/main/java/module-info.java
@@ -0,0 +1,20 @@
+module ai.timefold.solver.quarkus {
+ exports ai.timefold.solver.quarkus.bean;
+ exports ai.timefold.solver.quarkus;
+ exports ai.timefold.solver.quarkus.config;
+ exports ai.timefold.solver.quarkus.devui;
+ exports ai.timefold.solver.quarkus.gizmo;
+
+ requires ai.timefold.solver.core;
+ requires arc;
+ requires io.vertx.core;
+ requires jakarta.cdi;
+ requires jakarta.inject;
+ requires org.graalvm.nativeimage;
+ requires org.jspecify;
+ requires quarkus.core;
+ requires io.smallrye.config;
+ requires org.eclipse.microprofile.config;
+ requires org.jboss.logging;
+
+}
\ No newline at end of file
diff --git a/spring-integration/spring-boot-autoconfigure/src/main/java/module-info.java b/spring-integration/spring-boot-autoconfigure/src/main/java/module-info.java
new file mode 100644
index 00000000000..fea246c2072
--- /dev/null
+++ b/spring-integration/spring-boot-autoconfigure/src/main/java/module-info.java
@@ -0,0 +1,14 @@
+module ai.timefold.solver.spring.boot.autoconfigure {
+ requires ai.timefold.solver.jackson;
+ requires org.apache.commons.logging;
+ requires spring.beans;
+ requires spring.boot;
+ requires spring.boot.autoconfigure;
+ requires spring.boot.persistence;
+ requires spring.context;
+ requires spring.core;
+ requires tools.jackson.databind;
+ requires ai.timefold.solver.benchmark;
+ requires ai.timefold.solver.core;
+ requires org.jspecify;
+}
\ No newline at end of file
diff --git a/spring-integration/spring-boot-integration-test/src/main/java/module-info.java b/spring-integration/spring-boot-integration-test/src/main/java/module-info.java
new file mode 100644
index 00000000000..a002a95c561
--- /dev/null
+++ b/spring-integration/spring-boot-integration-test/src/main/java/module-info.java
@@ -0,0 +1,7 @@
+module ai.timefold.solver.spring.boot.integration.test {
+ requires ai.timefold.solver.core;
+ requires org.jspecify;
+ requires spring.boot;
+ requires spring.boot.autoconfigure;
+ requires spring.web;
+}
\ No newline at end of file
diff --git a/tools/benchmark-aggregator/src/main/java/module-info.java b/tools/benchmark-aggregator/src/main/java/module-info.java
new file mode 100644
index 00000000000..300ede41d0d
--- /dev/null
+++ b/tools/benchmark-aggregator/src/main/java/module-info.java
@@ -0,0 +1,5 @@
+module ai.timefold.solver.benchmark.aggregator {
+ requires java.desktop;
+ requires ai.timefold.solver.benchmark;
+ requires org.slf4j;
+}
\ No newline at end of file
diff --git a/tools/benchmark/src/main/java/module-info.java b/tools/benchmark/src/main/java/module-info.java
new file mode 100644
index 00000000000..01ba2c1e2a7
--- /dev/null
+++ b/tools/benchmark/src/main/java/module-info.java
@@ -0,0 +1,18 @@
+module ai.timefold.solver.benchmark {
+ requires ai.timefold.solver.jaxb;
+ requires ai.timefold.solver.persistence.common;
+ requires freemarker;
+ requires ai.timefold.solver.core;
+ requires org.jspecify;
+ requires jakarta.xml.bind;
+ requires org.slf4j;
+ requires micrometer.core;
+
+ exports ai.timefold.solver.benchmark.api;
+ exports ai.timefold.solver.benchmark.config;
+ exports ai.timefold.solver.benchmark.config.report;
+ exports ai.timefold.solver.benchmark.impl;
+ exports ai.timefold.solver.benchmark.impl.report;
+ exports ai.timefold.solver.benchmark.impl.result;
+ exports ai.timefold.solver.benchmark.impl.statistic.common;
+}
\ No newline at end of file
diff --git a/tools/migration/src/main/java/module-info.java b/tools/migration/src/main/java/module-info.java
new file mode 100644
index 00000000000..21e27bef811
--- /dev/null
+++ b/tools/migration/src/main/java/module-info.java
@@ -0,0 +1,4 @@
+module ai.timefold.solver.migration {
+ requires rewrite.core;
+ requires rewrite.java;
+}
\ No newline at end of file