+ * All classes in this package are part of the public API of this extension.
+ * Moreover, the extension is responsible for creating instances of these classes during the build phase.
+ */
+package ai.timefold.solver.quarkus.deployment.api;
diff --git a/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/BeanUtil.java b/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/BeanUtil.java
new file mode 100644
index 0000000000..c762015861
--- /dev/null
+++ b/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/BeanUtil.java
@@ -0,0 +1,32 @@
+package ai.timefold.solver.quarkus.bean;
+
+import java.util.Objects;
+
+import ai.timefold.solver.core.api.score.stream.ConstraintMetaModel;
+import ai.timefold.solver.core.api.solver.SolverFactory;
+import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraintStreamScoreDirectorFactory;
+import ai.timefold.solver.core.impl.solver.DefaultSolverFactory;
+
+public class BeanUtil {
+
+ public static ConstraintMetaModel buildConstraintMetaModel(SolverFactory> solverFactory) {
+ if (Objects.requireNonNull(solverFactory) instanceof DefaultSolverFactory> defaultSolverFactory) {
+ var scoreDirectorFactory = defaultSolverFactory.getScoreDirectorFactory();
+ if (scoreDirectorFactory instanceof AbstractConstraintStreamScoreDirectorFactory, ?> castScoreDirectorFactory) {
+ return castScoreDirectorFactory.getConstraintMetaModel();
+ } else {
+ throw new IllegalStateException(
+ "Cannot provide %s because the score director does not use the Constraint Streams API."
+ .formatted(ConstraintMetaModel.class.getSimpleName()));
+ }
+ } else {
+ throw new IllegalStateException(
+ "%s is not supported by the solver factory (%s)."
+ .formatted(ConstraintMetaModel.class.getSimpleName(), solverFactory.getClass().getName()));
+ }
+ }
+
+ private BeanUtil() {
+ throw new IllegalStateException("Utility class");
+ }
+}
diff --git a/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/DefaultTimefoldBeanProvider.java b/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/DefaultTimefoldBeanProvider.java
index c8dedd0c84..6a7ca96c92 100644
--- a/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/DefaultTimefoldBeanProvider.java
+++ b/quarkus-integration/quarkus/runtime/src/main/java/ai/timefold/solver/quarkus/bean/DefaultTimefoldBeanProvider.java
@@ -24,8 +24,6 @@
import ai.timefold.solver.core.api.solver.SolverManager;
import ai.timefold.solver.core.config.solver.SolverConfig;
import ai.timefold.solver.core.config.solver.SolverManagerConfig;
-import ai.timefold.solver.core.impl.score.stream.common.AbstractConstraintStreamScoreDirectorFactory;
-import ai.timefold.solver.core.impl.solver.DefaultSolverFactory;
import io.quarkus.arc.DefaultBean;
import io.quarkus.arc.Lock;
@@ -63,14 +61,8 @@