Fix 8.0.x build break introduced by 7.2.x merge (6ebc60c6d0)#15673
Open
jamesfredley wants to merge 7 commits into
Open
Fix 8.0.x build break introduced by 7.2.x merge (6ebc60c6d0)#15673jamesfredley wants to merge 7 commits into
jamesfredley wants to merge 7 commits into
Conversation
The merge from 7.2.x reintroduced three Spring Boot 3 era package names that are referenced as string literals (so the compiler cannot catch them). On the Grails 8 / Spring Boot 4 stack those classes live in new modules and the strings silently fail to match anything, so the @EnableAutoConfiguration exclusions they describe never take effect. * ApplicationClassInjector#CONDITIONAL_EXCLUSIONS pointed org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration at the wrong package; the class moved to org.springframework.boot.liquibase.autoconfigure in SB4. * GrailsApplicationCompilerAutoConfiguration injected an exclude for org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration into auto generated Application classes; that class moved to org.springframework.boot.jdbc.autoconfigure in SB4. The matching ApplicationClassInjectorSpec assertion is updated so the unit test catches future regressions of the liquibase entry. Assisted-by: claude-code:claude-opus-4-7
The 7.2.x merge brought back graphql-java.version=24.3 from a Grails 7 era stack where Spring Boot did not yet manage graphql-java. On the Grails 8 stack Spring Boot 4's spring-boot-dependencies BOM pins graphql-java at 25.0, so the SB BOM constraint always wins resolution. That left the Grails BOM declaring 24.3 while every project resolved 25.0, which validateDependencyVersions correctly flagged as drift on grails-data-hibernate5-docs and grails-data-mongodb-docs. Remove the redundant pin and the associated bomDependencies entry so spring-boot-dependencies is the single source of truth for graphql-java going forward. graphql-java-extended-scalars is not managed by SB, so that one is kept; its 24.0 release is compatible with graphql-java 25.0 and is already exercised by 254 grails-data-graphql-core tests. Assisted-by: claude-code:claude-opus-4-7
…le split The merge from 7.2.x moved this standalone Spring Boot demo from grails-data-graphql/examples/spring-boot-app/ to its current location and updated DemoApplication.groovy to import the Spring Boot 4 path org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration, but the build.gradle was not updated to actually depend on the module that class now lives in. The result was that :grails-test-examples-graphql-spring-boot-app :compileGroovy failed every CI job that runs ./gradlew build including the main Build Grails-Core matrix on every OS/JDK combo, Functional Tests, Hibernate5 Functional Tests and MongoDB Functional Tests, because all of those jobs depend on the root build target. The class must be on the runtime classpath (not compileOnly) because GORM's HibernateGormAutoConfiguration declares @AutoConfigureBefore([HibernateJpaAutoConfiguration]). Without it present at runtime the GORM auto config silently fails to load and HibernateDatastore never gets registered, which AuthorIntegrationTests exposes. Spring Boot's own JPA auto configuration is still suppressed by the existing @EnableAutoConfiguration(exclude = ...) annotation in DemoApplication, so GORM remains the sole Hibernate configurer. Assisted-by: claude-code:claude-opus-4-7
The 7.2.x merge brought back testRuntimeOnly 'org.slf4j:slf4j-simple' in grails-data-hibernate5/dbmigration/build.gradle. On the 8.0.x stack spring-boot-starter-tomcat transitively pulls in spring-boot-starter-logging which provides logback-classic, so leaving slf4j-simple on the integration test classpath gives SLF4J two competing bindings. Spring Boot's LogbackLoggingSystem aborts context startup with "LoggerFactory is not a Logback LoggerContext but Logback is on the classpath" the moment a Grails @Integration spec tries to load an ApplicationContext. Locally this took down all three specs in the module: AutoRunWithMultipleDataSourceSpec, AutoRunWithSingleDataSourceSpec, and DbUpdateCommandSpec. Removing the slf4j-simple line lets the SB provided Logback binding take over and all three pass again. jul-to-slf4j is left in place because Liquibase still uses java.util.logging and we want that output bridged to SLF4J. Assisted-by: claude-code:claude-opus-4-7
The merge from 7.2.x moved this example into the main settings.gradle for the first time on 8.0.x. The forward port surfaced three independent regressions that together made :integrationTest fail with "no tests discovered" and then with broken assertions once discovery was restored. 1) Spock test discovery. FooIntegrationSpec and BarIntegrationSpec were declared as `class X implements GraphQLSpec` without extending spock.lang.Specification, so JUnit's Spock engine never recognised them as tests. With nothing to run, the Grails @Integration bootstrapper never even tried to start a Spring context and Gradle 8.3+ raised "no tests discovered" rather than running them. Both specs are now `class X extends Specification implements GraphQLSpec` to match the sibling graphql examples. 2) Logback configuration format. The app shipped a logback.groovy. Logback's Groovy DSL was removed in logback-classic 1.5; on the 8.0.x stack that file is now read by the XML parser and aborts with SAXParseException "Content is not allowed in prolog". Convert the file to an equivalent logback.xml. 3) MongoDB infrastructure. The application.yml binds MongoDB at localhost:27017 with no fallback. The main Build Grails-Core CI job and local builds do not start a MongoDB, so the Spring context could not initialise even after test discovery was fixed. Add integrationTestImplementation 'org.apache.grails.testing:grails-testing-support-mongodb' so a MongoDB testcontainer is started for the integration test JVM and the host/port are injected via grails.mongodb.host. 4) GORM datastore lookup. Both specs asserted `session.datastore instanceof HibernateDatastore / MongoDatastore` inside a withNewSession closure. On the modern GORM/Hibernate stack the closure receives org.hibernate.internal.SessionImpl which does not expose a `datastore` property; the assertion blew up with MissingPropertyException. Replace with GormEnhancer.findStaticApi which is the public entry point that survives the upgrade. 5) graphql-java 25 scalar serialisation. MyGraphQLCustomizer declared Coercing<ObjectId, ObjectId> and returned an ObjectId from serialize. graphql-java 25 no longer toString()'s the returned scalar value during serialisation; it serialises the bean's structured properties (timestamp/date) instead. The custom scalar is changed to Coercing<ObjectId, String> and serialize now returns the 24 character hex form, matching the existing scalar description and what BarIntegrationSpec parses with new ObjectId. After these changes :integrationTest passes 2/2 locally on the merge commit with my other fixes applied. Assisted-by: claude-code:claude-opus-4-7
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request restores the 8.0.x branch build and CI health after the 7.2.x merge introduced Spring Boot 4 / Spring 7 / Jakarta-stack related breakages, by aligning dependency management and example/test modules with the new module/package layout and updated library behavior.
Changes:
- Align Spring Boot 4 auto-configuration exclusions and required dependencies (including the SB4 Hibernate/JPA module split).
- Remove a conflicting SLF4J binding and rely on Spring Boot’s Logback binding.
- Repair GraphQL multi-datastore example integration tests and scalar coercion behavior for graphql-java 25.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| grails-test-examples/graphql/spring-boot-app/build.gradle | Adds required spring-boot-hibernate dependency for SB4’s Hibernate auto-config module split. |
| grails-test-examples/graphql/grails-multi-datastore-app/src/main/groovy/myapp/MyGraphQLCustomizer.groovy | Updates ObjectId scalar coercing to match graphql-java 25 serialization expectations. |
| grails-test-examples/graphql/grails-multi-datastore-app/src/integration-test/groovy/myapp/FooIntegrationSpec.groovy | Fixes integration spec base class and updates datastore assertion to modern GORM API. |
| grails-test-examples/graphql/grails-multi-datastore-app/src/integration-test/groovy/myapp/BarIntegrationSpec.groovy | Same as above for Mongo-backed integration test. |
| grails-test-examples/graphql/grails-multi-datastore-app/grails-app/conf/logback.xml | Replaces deprecated Groovy Logback DSL config with XML config compatible with current stack. |
| grails-test-examples/graphql/grails-multi-datastore-app/grails-app/conf/logback.groovy | Removes deprecated Logback Groovy DSL configuration. |
| grails-test-examples/graphql/grails-multi-datastore-app/build.gradle | Adds MongoDB test support for integration tests via grails-testing-support-mongodb. |
| grails-shell-cli/src/main/groovy/org/grails/cli/boot/GrailsApplicationCompilerAutoConfiguration.java | Updates DataSource auto-config class reference to the SB4 package. |
| grails-data-hibernate5/dbmigration/build.gradle | Removes conflicting slf4j-simple test runtime binding and documents rationale. |
| grails-core/src/test/groovy/org/grails/compiler/injection/ApplicationClassInjectorSpec.groovy | Updates expected Liquibase auto-config exclusion class name for SB4. |
| grails-core/src/main/groovy/org/grails/compiler/injection/ApplicationClassInjector.groovy | Updates Liquibase auto-config exclusion class name for SB4. |
| dependencies.gradle | Stops pinning graphql-java so Spring Boot BOM remains the single source of truth. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The grails-gradle subproject's BOM derives its Groovy version from
`gradle-groovy.version` in dependencies.gradle, while the main grails-
core BOM uses `groovy.version`. Those drifted: main was on 4.0.32 but
gradle was still pinned at 4.0.31, so when the grails-gradle modules
resolved Groovy artifacts transitively they landed on 4.0.32 (the
highest available) while their own BOM still declared 4.0.31.
The Validate Dependency Versions CI job for `cd grails-gradle && ./gradlew
validateDependencyVersions` failed for grails-gradle-common,
grails-gradle-model, grails-gradle-plugins, and grails-gradle-tasks
with messages like:
org.apache.groovy:groovy-ant - resolved 4.0.32, expected 4.0.31
org.apache.groovy:groovy-groovydoc - resolved 4.0.32, expected 4.0.31
org.apache.groovy:groovy-templates - resolved 4.0.32, expected 4.0.31
org.apache.groovy:groovy-xml - resolved 4.0.32, expected 4.0.31
org.apache.groovy:groovy-docgenerator - resolved 4.0.32, expected 4.0.31
Align gradle-groovy.version with groovy.version so the two BOMs agree.
Assisted-by: claude-code:claude-opus-4-7
…use style Every other usage of grails-testing-support-mongodb in this repo uses testImplementation (or testImplementation project(:grails-testing-support -mongodb) for the internal modules). The integrationTest source set extends test under the grails-extension-gradle-config so the testcontainer support flows through to integration tests without needing the more specific integrationTestImplementation configuration. Spotted while auditing this PR against existing Gradle conventions in the repo. Assisted-by: claude-code:claude-opus-4-7
✅ All tests passed ✅🏷️ Commit: fcf1f99 Learn more about TestLens at testlens.app. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR fixes
Merge commit
6ebc60c6d0("Merge branch '7.2.x' into 8.0.x") plus pre-existing version drift turned every CI job on8.0.xred. Reproducing the failures locally surfaced six distinct problems that need to be addressed for8.0.xto build again on the Grails 8 / Spring Boot 4 / Spring 7 / Hibernate Jakarta stack. A seventh commit aligns the new file with house Gradle conventions discovered during a post-fix audit.CI failures and their fixes
Validate Dependency Versions- root projectgraphql-javapinned to24.3independencies.gradlewhile Spring Boot 4.0.5's BOM ships25.0; SB constraint wins and the validator flags the driftValidate Dependency Versions-cd grails-gradle && validateDependencyVersionsgradle-groovy.version=4.0.31drifted from maingroovy.version=4.0.32, transitive resolution upgraded all Groovy artifacts to 4.0.32 while grails-gradle BOM still expected 4.0.31Build Grails-Core (ubuntu/macos/windows, JDK 21+25):grails-test-examples-graphql-spring-boot-app:compileGroovycouldn't resolveorg.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfigurationbecause SB4 split it into a separate module that the new example'sbuild.gradledidn't depend onFunctional Tests,Hibernate5 Functional Tests,Mongodb Functional Tests:grails-test-examples-graphql-spring-boot-app:compileGroovyfailureHibernate5 Functional Tests(after compile fix):grails-data-hibernate5-dbmigration:integrationTestwas failing withLoggerFactory is not a Logback LoggerContext but Logback is on the classpathbecause the merge brought back a straytestRuntimeOnly 'org.slf4j:slf4j-simple'that competes with SB4's transitive Logback bindingCodeQL(./gradlew testClasses)CI - Groovy Joint Validation BuildLatent bugs caught while reproducing locally
These are not in any failed CI log yet because earlier failures stopped the build before reaching them, but they would surface immediately once the compile-blocking failures were fixed.
@EnableAutoConfigurationexclusion paths still pointed at Spring Boot 3 packages, silently failing to exclude anything in user appsApplicationClassInjector(Liquibase),ApplicationClassInjectorSpec(matching test),GrailsApplicationCompilerAutoConfiguration(DataSource)grails-test-examples-graphql-grails-multi-datastore-appdidn't compile/run cleanly on the 8.0.x stackextends Specification, deprecated Logback Groovy DSL config, no MongoDB testcontainer, deprecatedsession.datastoreGORM API, graphql-java 25's stricter scalarCoercingsignatureCommits
@EnableAutoConfiguration(excludeName=...)style string literals and the matching unit test assertion.bomDependenciesalias) so Spring Boot's 25.0 constraint is the single source of truth.implementationnotcompileOnlybecause GORM's@AutoConfigureBefore([HibernateJpaAutoConfiguration])needs the class loaded.extends Specification,logback.xml(Groovy DSL gone in Logback 1.5), MongoDB testcontainer viagrails-testing-support-mongodb, modernGormEnhancer.findStaticApi(...)access, andCoercing<ObjectId, String>for graphql-java 25.validateDependencyVersionstask stops failing on the Groovy artifact drift.grails-testing-support-mongodbin this repo declares it ontestImplementation, so this module follows suit (theintegrationTestsource set extendstestvia thegrails-extension-gradle-configso the testcontainer support still reaches integration tests).Local verification
All testing on the merge commit with these patches applied. JDK 21 (Corretto), Gradle 9.4.1,
GRADLE_OPTS=-Xms2G -Xmx5G.--rerun-tasks)./gradlew testClasses(CodeQL target)./gradlew validateDependencyVersions --continue(root)cd grails-gradle && ./gradlew validateDependencyVersions --continue./gradlew :grails-data-graphql-core:test./gradlew :grails-test-examples-graphql-spring-boot-app:check./gradlew :grails-data-hibernate5-dbmigration:integrationTest./gradlew :grails-core:test --tests ...ApplicationClassInjectorSpec./gradlew :grails-shell-cli:test./gradlew :grails-test-examples-graphql-{grails-test,grails-tenant,grails-docs,grails-multi-datastore,spring-boot}-appintegration tests./gradlew build :grails-shell-cli:installDist groovydoc --continue(matches CI Build Grails-Core command)HttpClientSupportSpec.httpPatchXml(server.verify()returnedfalse) that passes consistently in isolation; not introduced by this PRConvention audit
After the initial six commits, I audited every change in this PR against existing patterns in the repo:
build.gradlefiles (thebomDependencies['key']shortcut independencies.gradleis for BOM generation, not forbuild.gradleconsumption). All my additions use bare GAVs. Verdict: consistent.//-prefixed multi-line for inline explanations independencies.gradleandbuild.gradle. Verdict: consistent.logback.xml: matches the 37-line template used by all three sibling graphql apps. Verdict: consistent.extends Specification implements GraphQLSpec, no@Stepwisesince both feature methods are independent. Verdict: consistent with sibling specs.Coercing<Internal, External>generic signature: the in-repo built-ins use<T, T>because their Java type is already a valid wire value;<ObjectId, String>is the correct divergent-type form for a Java object that does not JSON-serialise to the wire form on its own (graphql-java 25 no longer toString's scalar return values). Verdict: consistent with the generic contract.org.springframework.boot.autoconfigure.{jdbc,orm,liquibase,batch,flyway,amqp,cache,jms,mail,data,security,web.reactive}.*produce zero remaining matches in the repo. The only remaining old-path reference is ingrails-data-neo4j/boot-pluginwhich is not included in the main build (the Neo4j module is not used). Verdict: complete.testImplementationvsintegrationTestImplementation: every other use ofgrails-testing-support-mongodbin the repo is ontestImplementation; commit 7 brings the multi-datastore-app in line.Known non-blocking notes
HttpClientSupportSpec.httpPatchXml(custom client variant) intermittently fails under heavy parallel load because Ersatz'sserver.verify()races with the JDKHttpClientrequest completion. The test predates the merge and passes in isolation. It is not a regression from this PR.org.grails.datastore.mapping.mongo.ProjectionsSpec(3 feature methods) is flaky when the full./gradlew buildis run on a machine where many tasks share the Docker daemon; root cause is aServiceLoadersingleton +@Sharedmanager interaction inGrailsDataTckSpecthat predates this PR and did not block CI onfc747cc76a. Out of scope for the merge-fix PR but worth tracking separately.grails-data-neo4j(separate Gradle build, not in main settings.gradle) has one remaining Spring Boot 3 import inNeo4jAutoConfiguration.groovy. The module is not used and not built by CI, so it is left for a separate Neo4j-focused PR.Fixes the CI breakage on 8.0.x introduced by 6ebc60c6d0 plus the gradle-groovy drift that surfaced the same week.