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]

Reply via email to