This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch test/abstract-datastore-initializer in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit eec3be04f04af61beb7b2ed2678f871fd9ed29bd Author: Walter Duque de Estrada <[email protected]> AuthorDate: Thu Aug 13 16:07:40 2026 -0500 Fix setDatabaseName being silently ignored on MongoDbDataStoreSpringInitializer MongodbGrailsPlugin sets initializer.databaseName = applicationName to default the Mongo database name to the Grails app's name, but that field was never read anywhere - every Grails+MongoDB app not explicitly setting grails.mongodb.databaseName silently got the wrong database. Adds applyDatabaseNameFallback(), called at the top of getBeanDefinitions() (the only method MongodbGrailsPlugin actually invokes - it doesn't go through configure()), which injects databaseName as a grails.mongodb.databaseName fallback property on `configuration` only when it was customized away from the class default and the configuration doesn't already specify one explicitly. Handles both configuration shapes this class accepts: ConfigurableEnvironment (the default and the Map-constructor path, both mutable via propertySources) and a generic Map (covering Grails' own Config, which this module can't depend on directly since it's designed to work standalone outside Grails - tested here via a minimal Map+PropertyResolver double instead). Co-Authored-By: Claude Sonnet 5 <[email protected]> --- .../MongoDbDataStoreSpringInitializer.groovy | 23 ++++ .../MongoDbDataStoreSpringInitializerSpec.groovy | 39 +++++++ ...ongoDbDataStoreSpringInitializerUnitSpec.groovy | 122 +++++++++++++++++++++ 3 files changed, 184 insertions(+) diff --git a/grails-data-mongodb/core/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy b/grails-data-mongodb/core/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy index 7672e0fe8e..98f43a5e90 100644 --- a/grails-data-mongodb/core/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy +++ b/grails-data-mongodb/core/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy @@ -25,6 +25,8 @@ import org.springframework.context.ApplicationContext import org.springframework.context.ApplicationEventPublisher import org.springframework.context.ConfigurableApplicationContext import org.springframework.context.support.GenericApplicationContext +import org.springframework.core.env.ConfigurableEnvironment +import org.springframework.core.env.MapPropertySource import org.springframework.util.ClassUtils import grails.mongodb.MongoEntity @@ -36,6 +38,7 @@ import org.grails.datastore.gorm.support.AbstractDatastorePersistenceContextInte import org.grails.datastore.gorm.support.DatastorePersistenceContextInterceptor import org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean import org.grails.datastore.mapping.mongo.MongoDatastore +import org.grails.datastore.mapping.mongo.config.MongoSettings import org.grails.datastore.mapping.mongo.connections.MongoConnectionSourceFactory /** @@ -83,8 +86,28 @@ class MongoDbDataStoreSpringInitializer extends AbstractDatastoreInitializer { return applicationContext } + /** + * Applies {@link #databaseName} as a {@code grails.mongodb.databaseName} fallback on + * {@link #configuration} when it was customized via {@link #setDatabaseName(String)} and the + * configuration does not already specify a database name explicitly. + */ + protected void applyDatabaseNameFallback() { + if (databaseName == DEFAULT_DATABASE_NAME || configuration.containsProperty(MongoSettings.SETTING_DATABASE_NAME)) { + return + } + if (configuration instanceof ConfigurableEnvironment) { + ((ConfigurableEnvironment) configuration).propertySources.addFirst( + new MapPropertySource('mongoDbDataStoreSpringInitializer.databaseName', [(MongoSettings.SETTING_DATABASE_NAME): databaseName]) + ) + } + else if (configuration instanceof Map) { + ((Map) configuration).put(MongoSettings.SETTING_DATABASE_NAME, databaseName) + } + } + @Override Closure getBeanDefinitions(BeanDefinitionRegistry beanDefinitionRegistry) { + applyDatabaseNameFallback() return { def callable = getCommonConfiguration(beanDefinitionRegistry, 'mongo') callable.delegate = delegate diff --git a/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerSpec.groovy b/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerSpec.groovy index 300d447ab7..5b33af0e38 100644 --- a/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerSpec.groovy +++ b/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerSpec.groovy @@ -61,6 +61,45 @@ class MongoDbDataStoreSpringInitializerSpec extends AutoStartedMongoSpec { mongoDatastore.destroy() } + void "Test setDatabaseName is honored as a fallback when no explicit grails.mongodb.databaseName is configured"() { + given: "an initializer with a customized database name and no explicit database name config" + def initializer = makeInitializer([ + (MongoSettings.SETTING_HOST): mongoHost, + (MongoSettings.SETTING_PORT): mongoPort, + ], Person) + initializer.setDatabaseName('fallbackDb') + + when: "the initializer is configured" + def applicationContext = initializer.configure() + def mongoDatastore = applicationContext.getBean(MongoDatastore) + + then: "the fallback database name is used" + mongoDatastore.getDefaultDatabase() == 'fallbackDb' + + cleanup: + mongoDatastore.destroy() + } + + void "Test setDatabaseName is ignored when grails.mongodb.databaseName is explicitly configured"() { + given: "an initializer with both a customized database name and an explicit database name config" + def initializer = makeInitializer([ + (MongoSettings.SETTING_DATABASE_NAME): 'explicit', + (MongoSettings.SETTING_HOST) : mongoHost, + (MongoSettings.SETTING_PORT) : mongoPort, + ], Person) + initializer.setDatabaseName('fallbackDb') + + when: "the initializer is configured" + def applicationContext = initializer.configure() + def mongoDatastore = applicationContext.getBean(MongoDatastore) + + then: "the explicit configuration wins over the fallback" + mongoDatastore.getDefaultDatabase() == 'explicit' + + cleanup: + mongoDatastore.destroy() + } + void "Test that MongoDbDatastoreSpringInitializer can setup GORM for MongoDB from scratch"() { when: "the initializer used to setup GORM for MongoDB" def initializer = makeInitializer([ diff --git a/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerUnitSpec.groovy b/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerUnitSpec.groovy index c708ac5c4e..3a8c694ec3 100644 --- a/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerUnitSpec.groovy +++ b/grails-data-mongodb/core/src/test/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializerUnitSpec.groovy @@ -21,6 +21,8 @@ package grails.mongodb.bootstrap import com.mongodb.MongoClientSettings import com.mongodb.client.MongoClient import grails.mongodb.MongoEntity +import org.grails.datastore.mapping.mongo.config.MongoSettings +import org.springframework.core.env.PropertyResolver import spock.lang.Specification /** @@ -109,6 +111,126 @@ class MongoDbDataStoreSpringInitializerUnitSpec extends Specification { then: initializer.mongo.is(client) } + + void 'applyDatabaseNameFallback does nothing when the database name was never customized'() { + given: + def initializer = new MongoDbDataStoreSpringInitializer() + + expect: + !initializer.configuration.containsProperty(MongoSettings.SETTING_DATABASE_NAME) + + when: + initializer.applyDatabaseNameFallback() + + then: + !initializer.configuration.containsProperty(MongoSettings.SETTING_DATABASE_NAME) + } + + void 'applyDatabaseNameFallback injects the customized database name into a ConfigurableEnvironment when not already set'() { + given: + def initializer = new MongoDbDataStoreSpringInitializer() + initializer.setDatabaseName('customDb') + + when: + initializer.applyDatabaseNameFallback() + + then: + initializer.configuration.getProperty(MongoSettings.SETTING_DATABASE_NAME) == 'customDb' + } + + void 'applyDatabaseNameFallback does not override an already-configured database name on a ConfigurableEnvironment'() { + given: + def initializer = new MongoDbDataStoreSpringInitializer() + initializer.configuration.propertySources.addFirst( + new org.springframework.core.env.MapPropertySource('test', [(MongoSettings.SETTING_DATABASE_NAME): 'explicit'])) + initializer.setDatabaseName('customDb') + + when: + initializer.applyDatabaseNameFallback() + + then: + initializer.configuration.getProperty(MongoSettings.SETTING_DATABASE_NAME) == 'explicit' + } + + void 'applyDatabaseNameFallback injects the customized database name into a Map-based PropertyResolver when not already set'() { + given: + def initializer = new MongoDbDataStoreSpringInitializer() + def config = new MapPropertyResolver() + initializer.configuration = config + initializer.setDatabaseName('customDb') + + when: + initializer.applyDatabaseNameFallback() + + then: + config.get(MongoSettings.SETTING_DATABASE_NAME) == 'customDb' + } + + void 'applyDatabaseNameFallback does not override an already-configured database name on a Map-based PropertyResolver'() { + given: + def initializer = new MongoDbDataStoreSpringInitializer() + def config = new MapPropertyResolver((MongoSettings.SETTING_DATABASE_NAME): 'explicit') + initializer.configuration = config + initializer.setDatabaseName('customDb') + + when: + initializer.applyDatabaseNameFallback() + + then: + config.get(MongoSettings.SETTING_DATABASE_NAME) == 'explicit' + } +} + +/** + * Minimal {@link PropertyResolver} backed directly by a {@link Map}, standing in for + * Grails' own {@code Config} type (which is both a {@code Map} and a {@code PropertyResolver}) + * without requiring a dependency on grails-core, which this module deliberately excludes. + */ +class MapPropertyResolver extends LinkedHashMap<String, Object> implements PropertyResolver { + + boolean containsProperty(String key) { + containsKey(key) + } + + @Override + String getProperty(String key) { + get(key) as String + } + + @Override + String getProperty(String key, String defaultValue) { + containsKey(key) ? get(key) as String : defaultValue + } + + @Override + def <T> T getProperty(String key, Class<T> targetType) { + get(key) as T + } + + @Override + def <T> T getProperty(String key, Class<T> targetType, T defaultValue) { + containsKey(key) ? get(key) as T : defaultValue + } + + @Override + String getRequiredProperty(String key) { + get(key) as String + } + + @Override + def <T> T getRequiredProperty(String key, Class<T> targetType) { + get(key) as T + } + + @Override + String resolvePlaceholders(String text) { + text + } + + @Override + String resolveRequiredPlaceholders(String text) { + text + } } class MappedThing implements MongoEntity<MappedThing> {
