jamesfredley opened a new pull request, #15397:
URL: https://github.com/apache/grails-core/pull/15397
## Summary
`GrailsApplicationContextCommandRunner.run()` passes ALL arguments—including
Grails command options like `--dataSource=secondary`—to `super.run(args)`
(which is `SpringApplication.run()`). Spring Boot's `CommandLinePropertySource`
interprets `--dataSource=secondary` as a property override, setting
`dataSource` to the String `"secondary"`. GORM expects `dataSource` to be a Map
(containing `url`, `username`, `password`, etc.), so the String value corrupts
the configuration and causes a startup failure.
## Bug Description
Running any Gradle `dbm*` task with a `--dataSource` argument fails:
```bash
./gradlew dbmStatus -Pargs="--dataSource=secondary"
```
**Error:**
```
Error creating bean with name 'hibernateDatastore':
Failed to instantiate [org.grails.orm.hibernate.HibernateDatastore]:
Constructor threw exception
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
at ... ConfigurationBuilder.buildRecurse(ConfigurationBuilder.groovy:394)
```
The `grailsw` CLI workaround works because it uses a different argument
parsing path that doesn't pass `--dataSource` through `SpringApplication.run()`:
```bash
./grailsw dbm-status --dataSource=secondary
# Works correctly
```
## Root Cause
In `GrailsApplicationContextCommandRunner.run()` (line 57), the full `args`
array is passed to `super.run(args)`:
```groovy
ctx = super.run(args) // args includes ["dbm-status",
"--dataSource=secondary", "com.example.Application"]
```
`super.run()` is `SpringApplication.run()`, which registers a
`CommandLinePropertySource` that interprets every `--key=value` argument as a
Spring property override. When `--dataSource=secondary` hits this, it sets the
`dataSource` property to the String `"secondary"`, overwriting GORM's Map-based
datasource configuration.
The `--dataSource` argument is intended for the Grails command (parsed
separately by `CommandLineParser.parse(args)`), NOT for Spring Boot.
## Fix
Added a `filterCommandOptions()` method that strips all `--` prefixed
arguments before passing to `super.run()`. The full args are still passed to
`CommandLineParser.parse(args)` so the Grails command receives its options:
```groovy
// Before (broken): Spring Boot sees --dataSource=secondary
ctx = super.run(args)
// After (fixed): Spring Boot only sees non-option args
String[] springBootArgs = filterCommandOptions(args)
ctx = super.run(springBootArgs)
CommandLine commandLine = new CommandLineParser().parse(args) // Command
still gets full args
```
The `filterCommandOptions()` method:
```groovy
protected static String[] filterCommandOptions(String[] args) {
List<String> filtered = new ArrayList<>()
for (String arg : args) {
if (!arg.startsWith('--')) {
filtered.add(arg)
}
}
filtered.toArray(new String[0])
}
```
This matches the existing pattern—Spring Boot should only receive the
application class name and the command name, not Grails command-specific
options.
## Files Changed
| File | Change |
|------|--------|
| `grails-console/.../GrailsApplicationContextCommandRunner.groovy` | Added
`filterCommandOptions()` method, called before `super.run()` |
| `grails-console/.../GrailsApplicationContextCommandRunnerSpec.groovy` |
**New** — 10 Spock tests for `filterCommandOptions()` |
| `grails-console/build.gradle` | Added `test-config.gradle` import for
JUnit Platform (Spock) |
## Test Coverage
10 Spock tests covering `filterCommandOptions()`:
1. **Filters single `--dataSource` option** — verifies the primary use case
2. **Filters multiple command options** — `--dataSource` + `--contexts`
stripped together
3. **No options passthrough** — args without `--` prefix pass through
unchanged
4. **Empty args** — returns empty array
5. **Only options (no command)** — all args stripped → empty array
6. **Mixed options and positional args** — positional args preserved,
options removed
7. **Flag without value** — `--verbose` (no `=`) also stripped
8. **Single dash args preserved** — `-v` is NOT stripped (only `--` prefix)
9. **Preserves argument order** — non-option args maintain original order
10. **Handles typical Gradle dbm task args** — realistic `["dbm-status",
"--dataSource=secondary", "com.example.Application"]` → `["dbm-status",
"com.example.Application"]`
All 10 tests pass.
## Example Application
**Repository:**
https://github.com/jamesfredley/grails-dbm-datasource-arg-conflict
Grails 7.0.7 app with two H2 in-memory databases (primary + secondary) and
Liquibase migration changelogs. Demonstrates:
1. `./gradlew bootRun` — app starts normally,
`http://localhost:8080/bugDemo/index` returns JSON confirming bug
2. `./gradlew dbmStatus` — default datasource succeeds
3. `./gradlew dbmStatus -Pargs="--dataSource=secondary"` — **FAILS** with
`ConfigurationBuilder` error
4. `./grailsw dbm-status --dataSource=secondary` — **WORKS** (workaround via
CLI)
## Environment Information
- Grails: 7.0.7
- GORM: 7.0.7
- Spring Boot: 3.5.10
- Groovy: 4.0.30
- JDK: 17 (Amazon Corretto)
## Version
7.0.7
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]