Skip to content

merge 7.0.x into 7.1.x#15434

Merged
jamesfredley merged 56 commits into7.1.xfrom
7.0.x
Feb 21, 2026
Merged

merge 7.0.x into 7.1.x#15434
jamesfredley merged 56 commits into7.1.xfrom
7.0.x

Conversation

@jamesfredley
Copy link
Contributor

No description provided.

jdaugherty and others added 30 commits February 10, 2026 12:02
…railsGradlePlugin

Add Java annotation processor (micronaut-inject-java) for projects using
grails-micronaut so that Java @singleton beans generate proper
BeanDefinitionReference classes at compile time. Groovy sources continue
to use the existing micronaut-inject-groovy AST transforms.

Configure bootJar and bootWar tasks to use LoaderImplementation.CLASSIC
as a convention default when Micronaut support is detected. The new
Spring Boot 3.2+ default loader is incompatible with Micronaut-Spring's
classpath scanning, causing NoClassDefFoundError at runtime when running
via java -jar.

Fixes #15207
Fixes #15211

Assisted-by: Claude Code <Claude@Claude.ai>
The Forge template already configured bootJar with CLASSIC loader but
was missing the equivalent bootWar configuration. WAR-packaged apps
deployed via java -jar would fail with the same Micronaut-Spring
classpath scanning issue as JAR-packaged apps.

Related to #15207

Assisted-by: Claude Code <Claude@Claude.ai>
Add the required ASF license header and replace TODO comment with a
See reference to satisfy the Forge project checkstyle TodoComment rule.

Assisted-by: Claude Code <Claude@Claude.ai>
Add MicronautBeanTypesSpec verifying that Java @singleton beans (via
annotation processor), Groovy @Factory/@bean beans (via AST transform),
and @ConfigurationProperties beans are all correctly bridged into the
Spring application context.

New test bean types:
- JavaSingletonService: Java class with @singleton (annotation processor path)
- FactoryCreatedService + ServiceFactory: Groovy @Factory/@bean pattern
- AppConfig: @ConfigurationProperties bound from application.yml

Also adds MicronautTestController and URL mapping for manual smoke
testing of bean injection across all registration mechanisms.

Assisted-by: Claude Code <Claude@Claude.ai>
…pgrade guide

Add notes to the 6.0.x upgrade guide warning users not to manually add
Micronaut annotation processors (now handled automatically by the Grails
Gradle Plugin) and explaining the automatic CLASSIC loader configuration
for bootJar/bootWar tasks.

References #15207, #15211

Assisted-by: Claude Code <Claude@Claude.ai>
SpringBootDevTools.shouldApply() now returns false when GrailsMicronaut
is selected, preventing the DefaultFeature from being auto-applied and
triggering GrailsMicronautValidator's incompatibility check.

Fixes Build Grails Forge CI failures on CreateAppSpec.

Assisted-by: Claude Code <Claude@Claude.ai>
…naut

Verifies no bean duplication occurs when micronaut-spring bridges Micronaut
beans into Spring context. Confirms bridged beans share the same singleton
instance across both contexts.

Assisted-by: Claude Code <Claude@Claude.ai>
- Use render([...] as JSON) instead of render(text: Map) for valid JSON output
- Fix singleton tests to use applicationContext.getBean() for proper scope verification
- Make JavaMessageProvider public and add interface-type injection test
- Correct capitalization of Spring Boot DevTools and Micronaut integration in docs

Assisted-by: Claude Code <Claude@Claude.ai>
Java requires public interfaces to be declared in a file matching the
interface name. Moves JavaMessageProvider out of JavaSingletonService.java
into its own JavaMessageProvider.java file.

Assisted-by: Claude Code <Claude@Claude.ai>
Replace the runtime AutoConfigurationImportFilter approach with a
compile-time AST transformation in ApplicationClassInjector. When
DatabaseMigrationGrailsPlugin is on the classpath, the exclusion is
added to @EnableAutoConfiguration(excludeName=...) during compilation -
the same mechanism already used for DataSourceAutoConfiguration,
ReactorAutoConfiguration, and HibernateJpaAutoConfiguration.

Opt-out via system property in gradle.properties:
  systemProp.grails.dbmigration.excludeLiquibaseAutoConfiguration=false

Assisted-by: Claude Code <Claude@Claude.ai>
 test

Remove auto-configured Micronaut annotation processors from
GrailsGradlePlugin per review feedback - they are incompatible with
Groovy incremental compilation and were never previously configured.
Projects with Java sources using Micronaut annotations must add the
annotationProcessor dependencies manually.

Add declarative @client interface and integration test to verify
Micronaut HTTP client beans are properly registered in the Grails
context. Add micronaut-http-client and micronaut-serde-jackson
dependencies to the micronaut test example, along with the required
annotationProcessor configuration for its Java sources.

All 33 micronaut integration tests pass.

Assisted-by: Claude Code <Claude@Claude.ai>
…atz mock

Add integration test that exercises the Micronaut @client(id='grails-self')
through the full service discovery and load balancing path using an ersatz
mock HTTP server as the backend endpoint.

Assisted-by: Claude Code <Claude@Claude.ai>
…lePlugin

The annotation processor (micronaut-inject-java) is required for Java
sources that use Micronaut annotations like @ConfigurationProperties
and @singleton. Removing it broke the issue-11767 plugin's
PluginJavaMicronautBean, which depends on compile-time code generation.

Assisted-by: Claude Code <Claude@Claude.ai>
…a sources

Micronaut annotation processors are incompatible with Groovy incremental
compilation, so they should not be auto-configured in GrailsGradlePlugin.
Instead, add them manually only to test apps that have Java sources using
Micronaut annotations (issue-11767 plugin has PluginJavaMicronautBean.java,
micronaut test app already had them configured).

Assisted-by: Claude Code <Claude@Claude.ai>
…3 to 3.20.0

Add version-conditional JVM arguments in GrailsGradlePlugin to suppress
warnings on modern JDKs:
- --sun-misc-unsafe-memory-access=allow for Java 23+ (JEP 471/498, #15343)
- --enable-native-access=ALL-UNNAMED for Java 24+ (JEP 472, #15216)

Override commons-lang3 from 3.17.0 (Spring Boot managed) to 3.20.0 in the
Grails BOM to fix LANG-1786 timezone warnings and CVE-2025-48924.

Includes Gradle TestKit functional tests verifying the args are applied
correctly based on toolchain version.

Assisted-by: Claude Code <Claude@Claude.ai>
Tests were hardcoding expected values for JDK 17 but CI also runs on
Java 25 where both compat flags are correctly applied. Compute expected
values dynamically from CURRENT_JDK.

Assisted-by: Claude Code <Claude@Claude.ai>
…connection)

Data Service methods using @where annotations or DetachedCriteria-based queries
(count, list, findBy*) were ignoring the class-level @transactional(connection)
annotation, causing queries to execute against the default datasource instead of
the specified connection.

Root cause: Both AbstractWhereImplementer and
AbstractDetachedCriteriaServiceImplementor called findConnectionId(newMethodNode)
instead of findConnectionId(abstractMethodNode). The newMethodNode belongs to the
generated $ServiceImplementation class which lacks the @transactional annotation,
while abstractMethodNode belongs to the original interface/abstract class where
the annotation is declared.

Additionally, in AbstractWhereImplementer the build() call was placed after
withConnection(), but DetachedCriteria.clone() (called internally by build) does
not copy the connectionName field, causing the connection setting to be lost.
Fixed by reordering build() before withConnection().

Fixes #15416

Assisted-by: Claude Code <Claude@Claude.ai>
AbstractHibernateGormStaticApi.exists() called criteriaQuery.from() twice,
creating a second query root that produced a cartesian product. The generated
SQL selected count(alias0) from Table alias1, Table alias0 where alias1.id=?,
scanning the entire table for every matching row instead of a simple count.

Reuse the existing queryRoot variable for the count select expression.

Fixes #14334

Assisted-by: Claude Code <Claude@Claude.ai>
Co-authored-by: Mattias Reichel <matrei@apache.org>
Co-authored-by: Mattias Reichel <matrei@apache.org>
Fix exists() cross-join caused by duplicate CriteriaQuery root
Add unit and functional tests verifying that @Query-annotated Data
Service methods (find-one, find-all, update) correctly route to
non-default datasources when @transactional(connection) is specified.

Tests cover both abstract class and interface service patterns using
FindOneStringQueryImplementer, FindAllStringQueryImplementer, and
UpdateStringQueryImplementer - previously untested code paths.

Assisted-by: Claude Code <Claude@Claude.ai>
jamesfredley and others added 24 commits February 20, 2026 15:52
Add TCK test (WhereQueryConnectionRoutingSpec) that validates @where
queries, count, list, and findBy operations route to the correct
datasource when using @transactional(connection). This ensures the
AbstractWhereImplementer fix is verified across all datastore
implementations, not just Hibernate.

- Add WhereRoutingItem domain and WhereRoutingItemService to TCK
- Extend GrailsDataTckManager with optional multi-datasource support
- Implement multi-datasource in Hibernate and MongoDB TCK managers
- Fix WhereQueryMultiDataSourceSpec cleanup (setup -> cleanup method)
- TCK test passes on Hibernate5, MongoDB, skipped on SimpleMap

Assisted-by: Claude Code <Claude@Claude.ai>
…ility

When Undertow is selected as the servlet container, undertow-core
transitively pulls in jboss-threads 3.7.0 which calls the terminally
deprecated sun.misc.Unsafe::objectFieldOffset in its static initializer,
producing a warning on Java 25. Pin jboss-threads to 3.9.2 as a
runtimeOnly dependency to resolve this.

Assisted-by: Claude Code <Claude@Claude.ai>
…r review

Address review feedback from jdaugherty:
- Replace afterEvaluate anti-pattern with project.plugins.withId('java')
- Move version resolution into configureEach callbacks so toolchain
  config is read lazily after build script evaluation
- Add project.logger.info for each JVM compatibility flag added

Assisted-by: Claude Code <Claude@Claude.ai>
…eton beans, and docs updates

- Add comprehensive ersatz-based integration tests for Micronaut declarative HTTP client
  covering GET, POST, PUT, DELETE, path variables, 404/500 error handling, and Accept headers
- Add full roundtrip integration tests (HTTP -> Grails controller -> service -> @client -> ersatz)
  for all CRUD operations, error propagation, sequential calls, custom headers, and large responses
- Add micronaut-singleton plugin with Java @singleton bean to verify plugin-contributed
  Micronaut beans are properly bridged into the Spring application context
- Add ExternalApiController and ExternalApiService demonstrating Grails service layer
  consuming external APIs via Micronaut declarative HTTP client
- Remove CLASSIC loader from Forge buildGradle template (no longer needed with plugin handling it)
- Update upgrading60x.adoc to clarify Micronaut plugin only adds Groovy support,
  annotation processors needed separately for Java, recommend split projects

63 integration tests pass (27 ersatz-based, 5 plugin bean, 31 existing)

Assisted-by: Claude Code <Claude@Claude.ai>
Add comprehensive ersatz-mocked integration tests covering every way a
Micronaut declarative HTTP client can be integrated into a Grails app:

- All HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, ANY
- Parameter binding: @QueryValue, @PathVariable, @Header, @CookieValue, @Body
- Return types: String, HttpResponse, CompletableFuture<T>, void
- Client config: @client(id), @client(id, path) for base path/API versioning
- Class-level @Header for automatic header injection on all methods
- @ClientFilter with @RequestFilter for auto-injecting auth tokens
- @retryable with ersatz sequential responses (503, 503, 200)
- Content types: JSON, plain text, XML
- Error handling: 401, 403, 404, 429, 500, 502, 503
- Ersatz features: delayed responses, sequential responses, listeners,
  call count verification, query/header/cookie matching, response cookies
- Full roundtrip tests: HTTP client -> Grails controller -> service ->
  Micronaut declarative client -> ersatz mock server

New files:
- MicronautAdvancedClient, MicronautHeaderClient (Phase 2)
- MicronautReactiveClient, MicronautPathClient, MicronautFilteredClient
- MicronautRetryableClient.java (Java for proper AOP annotation processing)
- AuthTokenClientFilter.java (@ClientFilter with @RequestFilter)
- MicronautErsatzAdvancedSpec (27 tests), MicronautErsatzPatternSpec (16 tests)

Total: 105 integration tests across 10 specs, all passing.

Assisted-by: Claude Code <Claude@Claude.ai>
Standardize the opt-out property name under the grails.autoconfigure.exclude
namespace per review feedback from @matrei, replacing the previous
grails.dbmigration.excludeLiquibaseAutoConfiguration name.

Assisted-by: Claude Code <Claude@Claude.ai>
fix: copy missing fields in AbstractDetachedCriteria.clone()
fix: add jboss-threads 3.9.2 to Undertow feature for Java 25 compatibility
…ainForForkTasks

Use plugins.withId('java') with configureEach instead of
afterEvaluate, matching the pattern used by
configureJavaCompatibilityArgs. The configureEach closure defers
execution until task realization (after evaluation), so the
toolchain check works without afterEvaluate.

Assisted-by: Claude Code <Claude@Claude.ai>
Replace internal GormEnhancer.findStaticApi/findInstanceApi calls
with the public domain class API (Item.secondary.withNewTransaction,
item.secondary.save) matching existing test conventions in
MultipleDataSourcesWithEventsSpec.

Assisted-by: Claude Code <Claude@Claude.ai>
Upgrade to Spring Boot 3.5.11
Restore Javadoc comments on ProductService, ProductDataService, and
DataServiceMultiDataSourceSpec that were inadvertently removed.

Assisted-by: Claude Code <Claude@Claude.ai>
Assisted-by: Claude Code <Claude@Claude.ai>
Add micronaut-groovy-only test example that validates grails-micronaut
works without explicit annotationProcessor dependencies or Java source
files. The Grails Gradle plugin auto-applies the required annotation
processors when grails-micronaut is on the classpath.

Includes bean injection, context coexistence, and qualifier tests
ported from the existing micronaut module with NamedService converted
from Java interface to Groovy interface.

Assisted-by: Claude Code <Claude@Claude.ai>
Copilot AI review requested due to automatic review settings February 21, 2026 23:38
@jamesfredley jamesfredley merged commit 2988347 into 7.1.x Feb 21, 2026
91 of 94 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges changes from the 7.0.x maintenance branch into 7.1.x. The changes include:

Changes:

  • New Micronaut integration test examples with Ersatz mock server testing
  • Java 23+ and 24+ compatibility JVM arguments for Test and JavaExec tasks
  • Grails Micronaut plugin improvements (annotation processor handling, Spring Boot DevTools incompatibility)
  • GORM multi-datasource connection routing fixes for @Where queries and @Query methods
  • Hibernate exists() cross-join fix (issue #14334)
  • Automatic LiquibaseAutoConfiguration exclusion when database-migration plugin is present
  • Dependency updates (Spring Boot 3.5.10 → 3.5.11, grails-spring-security 7.0.1 → 7.0.2)

Reviewed changes

Copilot reviewed 97 out of 101 changed files in this pull request and generated no comments.

Show a summary per file
File Description
settings.gradle Adds two new test example projects: micronaut-groovy-only and plugins/micronaut-singleton
grails-test-examples/micronaut/* Comprehensive Micronaut integration tests with Ersatz mock server, declarative clients, bean injection
grails-test-examples/micronaut-groovy-only/* Pure Groovy Micronaut beans test (validates AST transform without Java annotation processor)
grails-test-examples/plugins/micronaut-singleton/* Plugin providing @Singleton bean to verify cross-context bridge
grails-gradle/.../GrailsGradlePlugin.groovy Java 23/24 compatibility JVM args, toolchain handling, CLASSIC boot loader for Micronaut
grails-forge/.../SpringBootDevTools.java Excludes spring-boot-devtools when grails-micronaut is selected
grails-forge/.../SpringBootUndertowFeature.java Adds jboss-threads dependency for Java 25 compatibility
grails-forge/.../GrailsMicronautValidator.java Validates incompatibility between grails-micronaut and spring-boot-devtools
grails-micronaut/.../GrailsMicronautGrailsPlugin.groovy Code formatting improvements, removes micronaut-inject-java compileOnlyApi
grails-datamapping-core/.../AbstractWhereImplementer.groovy Fixes connection routing by calling withConnection before build
grails-datamapping-core/.../AbstractDetachedCriteria.groovy Clone preserves connectionName, lazyQuery, associationCriteriaMap
grails-data-hibernate5/.../AbstractHibernateGormStaticApi.groovy Fixes exists() cross-join by using queryRoot instead of creating new from()
grails-core/.../ApplicationClassInjector.groovy Automatic conditional exclusion of LiquibaseAutoConfiguration
grails-doc/.../upgrading60x.adoc Documents Micronaut integration, annotation processor requirements, DevTools incompatibility
grails-doc/.../automaticDatabaseMigration.adoc Documents automatic LiquibaseAutoConfiguration exclusion
dependencies.gradle Spring Boot 3.5.10 → 3.5.11, adds commons-lang3
gradle.properties Adds ersatzVersion=4.0.1, updates grailsSpringSecurityVersion to 7.0.2-SNAPSHOT

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants