From 1a3b0f79c47043bb37c99707b4f129fcbe2018b6 Mon Sep 17 00:00:00 2001 From: Matthias Kurz Date: Thu, 8 Oct 2026 15:18:54 +0200 Subject: [PATCH] Allow disabling Play's EvolutionsModule EbeanDynamicEvolutions required an EvolutionsConfig to be injected, which only Play's EvolutionsModule binds. So with that module disabled, e.g. via play.modules.disabled += "play.api.db.evolutions.EvolutionsModule", the application failed to start with "No implementation for EvolutionsConfig was bound". Now it looks up the EvolutionsConfig only when generating the evolution scripts, which only happens with the EvolutionsModule enabled, and respects any custom binding. The existing public constructor taking an EvolutionsConfig, used e.g. with compile-time DI, is kept. --- .../play/db/ebean/EbeanDynamicEvolutions.java | 25 ++++++++++++-- .../EbeanWithoutEvolutionsModuleTest.java | 33 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 play-ebean/src/test/java/play/db/ebean/EbeanWithoutEvolutionsModuleTest.java diff --git a/play-ebean/src/main/java/play/db/ebean/EbeanDynamicEvolutions.java b/play-ebean/src/main/java/play/db/ebean/EbeanDynamicEvolutions.java index 80a3b961..6f44edd6 100644 --- a/play-ebean/src/main/java/play/db/ebean/EbeanDynamicEvolutions.java +++ b/play-ebean/src/main/java/play/db/ebean/EbeanDynamicEvolutions.java @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Singleton; import play.Environment; @@ -22,6 +23,7 @@ import play.api.db.evolutions.Evolutions$; import play.api.db.evolutions.EvolutionsConfig; import play.inject.ApplicationLifecycle; +import play.inject.Injector; /** A Play module that automatically manages Ebean configuration. */ @Singleton @@ -30,16 +32,34 @@ public class EbeanDynamicEvolutions extends DynamicEvolutions { private final EbeanConfig config; private final Environment environment; - private final EvolutionsConfig evolutionsConfig; + private final Supplier evolutionsConfig; private final Map databases = new HashMap<>(); - @Inject public EbeanDynamicEvolutions( EbeanConfig config, Environment environment, ApplicationLifecycle lifecycle, EvolutionsConfig evolutionsConfig) { + this(config, environment, lifecycle, () -> evolutionsConfig); + } + + @Inject + public EbeanDynamicEvolutions( + EbeanConfig config, + Environment environment, + ApplicationLifecycle lifecycle, + Injector injector) { + // Only needed (and bound) when Play's EvolutionsModule, which is optional, generates the + // scripts + this(config, environment, lifecycle, () -> injector.instanceOf(EvolutionsConfig.class)); + } + + private EbeanDynamicEvolutions( + EbeanConfig config, + Environment environment, + ApplicationLifecycle lifecycle, + Supplier evolutionsConfig) { this.config = config; this.environment = environment; this.evolutionsConfig = evolutionsConfig; @@ -64,6 +84,7 @@ public void create() { if (environment.isProd()) { return; } + EvolutionsConfig evolutionsConfig = this.evolutionsConfig.get(); config .serverConfigs() .forEach( diff --git a/play-ebean/src/test/java/play/db/ebean/EbeanWithoutEvolutionsModuleTest.java b/play-ebean/src/test/java/play/db/ebean/EbeanWithoutEvolutionsModuleTest.java new file mode 100644 index 00000000..f0f28724 --- /dev/null +++ b/play-ebean/src/test/java/play/db/ebean/EbeanWithoutEvolutionsModuleTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. + */ + +package play.db.ebean; + +import static org.junit.Assert.assertEquals; + +import io.ebean.DB; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import play.Application; +import play.api.db.evolutions.EvolutionsModule; +import play.inject.guice.GuiceApplicationBuilder; +import play.test.Helpers; + +public class EbeanWithoutEvolutionsModuleTest { + + @Test + public void startsWithoutPlaysEvolutionsModule() { + Application app = + new GuiceApplicationBuilder() + .disable(EvolutionsModule.class) + .configure( + Map.of( + "db.default.driver", "org.h2.Driver", + "db.default.url", "jdbc:h2:mem:play-ebean-without-evolutions", + "ebean.default", List.of("play.db.ebean.models.first.*"))) + .build(); + Helpers.running(app, () -> assertEquals("default", DB.getDefault().name())); + } +}