jdaugherty opened a new pull request, #16469:
URL: https://github.com/apache/grails-core/pull/16469

   ## Problem
   
   Grails adds a `String -> Resource` converter to the conversion service that 
Spring Boot installs on both the environment and the bean factory. The bean 
factory consults that conversion service before its default property editors, 
and once `String -> Resource` exists, Spring's generic String, array and 
collection converters can reach `Resource[]` by converting one element at a 
time. A location pattern such as `classpath*:META-INF/foo.properties` therefore 
becomes a single `Resource` whose path is the literal pattern, instead of every 
matching resource. Spring's pattern-aware `ResourceArrayPropertyEditor` is 
never used. The conversion succeeds, because creating a `Resource` does not 
require it to exist, so the failure only shows up when the resource is opened:
   
   ```
   Could not open ServletContext resource 
[/classpath*:META-INF/spring.integration.properties]
   ```
   
   The converter dates from Grails 3.2, and the behavior is the same on Grails 
7 / Boot 3. It became visible with Spring Boot 4:
   
   - Spring Integration registers an `integrationGlobalProperties` bean backed 
by a `PropertiesFactoryBean` whose `locations` is 
`classpath*:META-INF/spring.integration.properties`, an optional override that 
normally matches nothing. It only does so when no `integrationGlobalProperties` 
bean exists yet.
   - With Boot 3, `spring-boot-autoconfigure` shipped 
`IntegrationAutoConfiguration`, which defines that bean itself. Spring 
Integration's definition was skipped as a side effect, so its pattern never 
went through Grails' conversion.
   - Boot 4 moved that auto-configuration into `spring-boot-integration`. An 
application that depends on `spring-integration-core` without that module now 
gets Spring Integration's own definition, and startup fails as shown above.
   
   Adding `spring-boot-integration` avoids the Spring Integration case. 
However, any `Resource[]` bean property given a pattern is affected: a 
`PropertiesFactoryBean`, `locations` lists in `resources.groovy` or XML, 
library-defined beans, and `config.getProperty(name, Resource[])`.
   
   A controlled reproducer (a minimal `GrailsApp` plus 
`spring-integration-core` with `@EnableIntegration`) confirms this:
   
   | Grails / Boot | `integrationGlobalProperties` from | Result |
   |---|---|---|
   | 7.2.4 / 3.5 | Boot `IntegrationAutoConfiguration` | starts |
   | 7.2.4 / 3.5, no auto-configuration | Spring Integration | fails |
   | 8.0.0-RC1 / 4.1 | Spring Integration | fails |
   | 8.0.0-RC1 / 4.1 + `spring-boot-integration` | Boot 
`IntegrationAutoConfiguration` | starts |
   
   The conversion itself behaves the same on Spring 6.2.19/Boot 3.5.16 and 
Spring 7.0.9/Boot 4.1.1.
   
   ## Change
   
   - Register a `Resource[]` converter for `String`, `Object[]` and 
`Collection` sources. It delegates to Spring's `ResourceArrayPropertyEditor` 
with the application context and environment, so it keeps Spring's semantics: 
patterns expand to every match, or to an empty array when nothing matches, 
comma-delimited Strings hold several patterns, placeholders are resolved, and 
`Resource` elements are kept. Sources with other element types still fall 
through to the existing converters. `String -> Resource` is unchanged.
   - Register the converter set in one place, shared by 
`GrailsEarlyPluginRegistrationPostProcessor` and 
`GrailsApplicationPostProcessor`. Previously each registered its own copy, so 
the early phase, which plugin `doWithSpring` config reads run in, would have 
missed the array converter.
   - Upgrade guide: add the `Resource[]` behavior change, and note that Spring 
Integration auto-configuration now lives in `spring-boot-integration`.
   
   ## Tests
   
   `GrailsResourceConversionSpec` exercises:
   
   - a real `GrailsApp` start with application `doWithSpring` beans
   - the application lifecycle without the early phase
   - the early phase alone, with plugin `doWithSpring` beans and a config read
   
   It covers a Spring Integration-shaped unmatched `classpath*:` 
`PropertiesFactoryBean`, single patterns, comma lists, lists, arrays, 
placeholders, `config.getProperty(name, Resource[])`, and single `Resource` 
properties.
   
   Mutation-checked:
   
   - removing the array converter fails the whole spec
   - giving the early phase only the scalar converter fails the early-phase test
   - restricting the converter to `String` sources fails the list, array and 
lifecycle cases
   
   `:grails-core:test` (714 tests, 0 failures), `codeStyle` and 
`validateRepositoryConventions` pass locally.
   


-- 
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