From 6d9f1aa8203e11d84b916555c0dc369c28c0b0ba Mon Sep 17 00:00:00 2001 From: Matthias Kurz Date: Thu, 8 Oct 2026 15:18:41 +0200 Subject: [PATCH 1/2] Ignore Ebean settings below ebean.* that are no lists of models Besides conf/application.conf, Play also loads conf/application.properties, where Ebean (which doesn't read application.conf) expects its own settings, e.g. ebean.migration.run=false. Play Ebean then took such a setting for a list of models, and failed with e.g. "migration has type OBJECT rather than LIST", at runtime as well as when the sbt plugin loads the models to enhance. Now Play Ebean only uses the strings and lists below ebean.* as models and ignores everything else. As Ebean doesn't read application.conf, ignored settings from a .conf file get logged as a warning. --- .../working/javaGuide/main/sql/JavaEbean.md | 2 ++ .../java/play/db/ebean/EbeanParsedConfig.java | 18 +++++++++++++++++- .../play/db/ebean/EbeanParsedConfigTest.java | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/manual/working/javaGuide/main/sql/JavaEbean.md b/docs/manual/working/javaGuide/main/sql/JavaEbean.md index e60eddf2..b2e04118 100644 --- a/docs/manual/working/javaGuide/main/sql/JavaEbean.md +++ b/docs/manual/working/javaGuide/main/sql/JavaEbean.md @@ -45,6 +45,8 @@ As an example, the fairly common problem of reducing the sequence batch size in Make sure that such a class is covered by an `ebean.` config line, for example by putting it into the `models` package. Play Ebean registers the configured classes with Ebean explicitly, which disables Ebean's own classpath scanning, so Ebean silently ignores any `ServerConfigStartup` that is not covered. +Note that Ebean doesn't read Play's `conf/application.conf`, so put Ebean's own settings (e.g. `ebean.migration.run`) into `conf/application.yaml` or `conf/application.properties`. Play loads `conf/application.properties` as well, but Play Ebean only uses the `ebean.` config lines that list models, and ignores any other `ebean.` setting. + Note that Ebean will also make use of a `conf/orm.xml` file (if present), to configure ``. #### Using a read replica diff --git a/play-ebean/src/main/java/play/db/ebean/EbeanParsedConfig.java b/play-ebean/src/main/java/play/db/ebean/EbeanParsedConfig.java index 0caa661c..6a25f0e9 100644 --- a/play-ebean/src/main/java/play/db/ebean/EbeanParsedConfig.java +++ b/play-ebean/src/main/java/play/db/ebean/EbeanParsedConfig.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import play.Logger; /** * The raw parsed config from Ebean, as opposed to the EbeanConfig which actually requires starting @@ -18,6 +19,8 @@ */ public class EbeanParsedConfig { + private static final Logger.ALogger LOGGER = Logger.of(EbeanParsedConfig.class); + private final String defaultDatasource; private final Map> datasourceModels; @@ -118,8 +121,21 @@ public static EbeanParsedConfig parseFromConfig(Config config) { if (raw.valueType() == ConfigValueType.STRING) { // Support legacy comma separated string models = Arrays.asList(((String) raw.unwrapped()).split(",")); - } else { + } else if (raw.valueType() == ConfigValueType.LIST) { models = ebeanConfig.getStringList(key); + } else { + // No models, but e.g. one of Ebean's own settings, which Play also loads from + // conf/application.properties + if (raw.origin().description().contains(".conf")) { + LOGGER.warn( + "Ignoring {}.{} ({}), as it's no list of models and Ebean doesn't read" + + " Play's configuration. Put Ebean's own settings into" + + " conf/application.yaml or conf/application.properties instead.", + ebeanConfigKey, + key, + raw.origin().description()); + } + return; } datasourceModels.put(key, models); diff --git a/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java b/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java index 1987e384..89ad3b2f 100644 --- a/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java +++ b/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java @@ -43,6 +43,24 @@ public void withDataSources() { assertThat(config.getDatasourceModels().get("other"), hasItems("c")); } + @Test + public void ignoresEbeanSettings() { + // Ebean's own settings, e.g. from conf/application.properties, which Play loads too + EbeanParsedConfig config = + parse( + ImmutableMap.of( + "ebean.default", + Collections.singletonList("a"), + "ebean.other.databasePlatformName", + "h2", + "ebean.migration.run", + false, + "ebean.dumpMetricsOnShutdown", + true)); + assertThat(config.getDatasourceModels().keySet(), equalTo(Collections.singleton("default"))); + assertThat(config.getDatasourceModels().get("default"), hasItems("a")); + } + @Test public void commaSeparatedModels() { EbeanParsedConfig config = parse(ImmutableMap.of("ebean.default", "a,b")); From 85159db44c81670c5f719334f286203dddb76059 Mon Sep 17 00:00:00 2001 From: Matthias Kurz Date: Thu, 8 Oct 2026 15:34:31 +0200 Subject: [PATCH 2/2] Test Ebean settings from application.properties, clarify the docs In conf/application.properties, all values are strings. So while nested Ebean settings like ebean.migration.run get ignored, a setting directly below ebean.*, like ebean.dumpMetricsOnShutdown=true, still looks like a list of models, of an Ebean server without a database, which gets skipped. Test that with a configuration in properties syntax, and say so in the docs, recommending conf/application.yaml for such settings. --- .../working/javaGuide/main/sql/JavaEbean.md | 2 +- .../play/db/ebean/EbeanParsedConfigTest.java | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/manual/working/javaGuide/main/sql/JavaEbean.md b/docs/manual/working/javaGuide/main/sql/JavaEbean.md index b2e04118..ef7102ee 100644 --- a/docs/manual/working/javaGuide/main/sql/JavaEbean.md +++ b/docs/manual/working/javaGuide/main/sql/JavaEbean.md @@ -45,7 +45,7 @@ As an example, the fairly common problem of reducing the sequence batch size in Make sure that such a class is covered by an `ebean.` config line, for example by putting it into the `models` package. Play Ebean registers the configured classes with Ebean explicitly, which disables Ebean's own classpath scanning, so Ebean silently ignores any `ServerConfigStartup` that is not covered. -Note that Ebean doesn't read Play's `conf/application.conf`, so put Ebean's own settings (e.g. `ebean.migration.run`) into `conf/application.yaml` or `conf/application.properties`. Play loads `conf/application.properties` as well, but Play Ebean only uses the `ebean.` config lines that list models, and ignores any other `ebean.` setting. +Note that Ebean doesn't read Play's `conf/application.conf`, so put Ebean's own settings (e.g. `ebean.migration.run`) into `conf/application.yaml`, which only Ebean reads, or into `conf/application.properties`. Play loads `conf/application.properties` as well, and Play Ebean ignores nested settings from there, like `ebean.migration.run`. However, a setting directly below `ebean.`, like `ebean.dumpMetricsOnShutdown=true`, looks like a list of models to Play Ebean, which only skips it because there's no database of that name. So prefer `conf/application.yaml` for such settings. Note that Ebean will also make use of a `conf/orm.xml` file (if present), to configure ``. diff --git a/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java b/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java index 89ad3b2f..fd8ea008 100644 --- a/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java +++ b/play-ebean/src/test/java/play/db/ebean/EbeanParsedConfigTest.java @@ -9,9 +9,12 @@ import com.google.common.collect.ImmutableMap; import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigParseOptions; +import com.typesafe.config.ConfigSyntax; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.Set; import org.junit.*; public class EbeanParsedConfigTest { @@ -43,9 +46,28 @@ public void withDataSources() { assertThat(config.getDatasourceModels().get("other"), hasItems("c")); } + @Test + public void ignoresEbeanSettingsFromProperties() { + // Play also loads conf/application.properties, where all values are strings + EbeanParsedConfig config = + EbeanParsedConfig.parseFromConfig( + ConfigFactory.parseString( + "ebean.default=a\n" + + "ebean.other.databasePlatformName=h2\n" + + "ebean.migration.run=false\n" + + "ebean.dumpMetricsOnShutdown=true\n", + ConfigParseOptions.defaults().setSyntax(ConfigSyntax.PROPERTIES)) + .withFallback(ConfigFactory.defaultReference())); + // Nested settings get ignored, while a setting directly below ebean. looks like a list of + // models (of an Ebean server without a database, so it gets skipped later on) + assertThat( + config.getDatasourceModels().keySet(), equalTo(Set.of("default", "dumpMetricsOnShutdown"))); + assertThat(config.getDatasourceModels().get("default"), hasItems("a")); + } + @Test public void ignoresEbeanSettings() { - // Ebean's own settings, e.g. from conf/application.properties, which Play loads too + // Ebean's own settings in a .conf file (which Ebean doesn't read, though) EbeanParsedConfig config = parse( ImmutableMap.of(