Restore micronaut-jackson-databind for grails-forge-web-netty JSON runtime#15651
Merged
jamesfredley merged 1 commit intoMay 8, 2026
Merged
Conversation
…ntime After PR apache#15647 + apache#15648 fixed dockerBuildNative + Cloud Run startup for the analytics service, both Forge deploy workflows finally finished green and pushed `next.grails.org` (8.0.0-M1 hotfix branch) and `prev-snapshot.grails.org` (8.0.x) revisions live. start.grails.org still does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because both backends return: $ curl -i -H 'Origin: https://start.grails.org' https://next.grails.org/versions HTTP/1.1 500 Internal Server Error Content-Type: application/json ... {"_embedded":{"errors":[{"message":"Internal Server Error: Error encoding object [org.grails.forge.api.VersionDTO@..] to JSON: No serializable introspection present for type VersionDTO. Consider adding Serdeable.Serializable annotate to type VersionDTO."}]}, "message":"Internal Server Error"} Reproduced locally (`docker run grails-forge-local:web-netty` against the GraalVM Community 21.0.2-ol9 native image with CORS_ALLOWED_ORIGIN set, then `curl -H 'Origin: https://start.grails.org' /versions`) - identical 500. Root cause: PR apache#15365 review feedback (commit e1f3013, "Address PR review feedback: telemetry override, forge BOM adoption, publish plugin bump") swapped grails-forge-web-netty's runtime JSON dependency: - runtimeOnly 'io.micronaut:micronaut-jackson-databind' + runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson' with the rationale that "the forge stack is a Micronaut 4 serde- jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template". That is not yet true: every DTO returned by the Forge controllers (VersionDTO, ApplicationTypeDTO, FeatureDTO, FeatureList, SelectOptionsDTO, GormImplDTO, JdkVersionDTO, LanguageDTO, ServletImplDTO, DevelopmentReloadingDTO, GitHubCreateDTO, PreviewDTO, ApplicationTypeList, LinkDTO, the abstract Linkable parent, ...) carries `@Introspected` only - none of them are `@Serdeable` or registered via `@SerdeImport`. Micronaut Serde correctly rejects @Introspected-only classes at runtime, while Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behind next.grails.org and prev-snapshot.grails.org into a 500, which is why Forge UI's `versions` fetch is empty for those backends and 8.0.0-M1 is missing from the start.grails.org Grails Version selector. The other Forge modules (forge-api tests, forge-core, analytics- postgres) all still use micronaut-jackson-databind; web-netty was the only inconsistency. Restore web-netty to micronaut-jackson-databind so the runtime matches the rest of the forge stack and the existing @introspected DTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with @Serdeable / @SerdeImport. Verified locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use: $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/versions HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org Vary: Origin Access-Control-Allow-Credentials: true content-type: application/json ... {"_links":{"self":{"href":"http://.../versions","templated":false}}, "versions":{...,"grails.version":"8.0.0-M1",...}} $ curl -i -H 'Origin: https://start.grails.org' http://localhost:18080/select-options HTTP/1.1 200 OK Access-Control-Allow-Origin: https://start.grails.org ... Endpoints serve JSON cleanly; CORS allow-origin header is present; the start.grails.org Grails Version selector will pick up 8.0.0-M1 once next.grails.org is redeployed from this commit. Assisted-by: claude-code:claude-4.7-opus
Contributor
There was a problem hiding this comment.
Pull request overview
Restores Jackson Databind as the JSON runtime for the grails-forge-web-netty Micronaut service so Forge’s existing @Introspected DTOs can be serialized successfully (avoiding Micronaut Serde’s requirement for @Serdeable / @SerdeImport across returned types).
Changes:
- Swap the runtime JSON dependency from
io.micronaut.serde:micronaut-serde-jacksonback toio.micronaut:micronaut-jackson-databind. - Add an in-file comment explaining why Serde cannot be used yet without an end-to-end DTO annotation/import migration.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+43
to
+47
| // / prev-snapshot.grails.org. The rest of the forge stack (forge-api, | ||
| // forge-core, analytics-postgres) still depends on | ||
| // io.micronaut:micronaut-jackson-databind, so keep the netty service on | ||
| // the same JSON runtime to match. If forge ever migrates to Serde end- | ||
| // to-end, every DTO needs @Serdeable / @SerdeImport at the same time. |
|
Here's a reworded version of the comment in the build.gradle file to accurately reflect the dependency usage, incorporating your details about the other forge components. grails-forge/grails-forge-web-netty/build.gradle |
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.
Summary
PRs #15646 / #15647 / #15648 fixed the broken
dockerBuildNativeand Cloud Run startup paths so the Forge deploy workflows (prev-snapshot run 25579824416, next run 25579825356) finished green and thenext.grails.org(8.0.0-M1) andprev-snapshot.grails.org(8.0-SNAPSHOT) Cloud Run revisions went live.start.grails.orgstill does not list 8.0.0-M1 / 8.0-SNAPSHOT in the Grails Version selector, though, because the freshly deployed backends both return HTTP 500 on every JSON endpoint:The frontend's
grails-version-feed.jsonexplicitly fans out tolatest.grails.org,snapshot.grails.org,next.grails.org,prev.grails.org, andprev-snapshot.grails.org. The first three are 7.1.x release builds and return 200; the latter two are our new 8.0.x builds and return 500, so the version selector skips them and the only Grails versions visible atstart.grails.orgtoday are7.1.1,7.1.2-SNAPSHOT,7.0.11. The browser additionally reports CORS errors on those 500 responses because Micronaut's error path bypasses the CORS filter (separate hardening, out of scope for this PR).Root cause
PR #15365 review feedback (commit
e1f3013070) swapped the runtime JSON dependency ingrails-forge-web-netty/build.gradle:with the rationale that "the forge stack is a Micronaut 4 serde-jackson application; the legacy jackson-databind runtime was a copy-paste from an earlier generator template." That is not yet true: every DTO returned by the Forge controllers (
VersionDTO,ApplicationTypeDTO,FeatureDTO,FeatureList,SelectOptionsDTO,GormImplDTO,JdkVersionDTO,LanguageDTO,ServletImplDTO,DevelopmentReloadingDTO,GitHubCreateDTO,PreviewDTO,ApplicationTypeList,LinkDTO, the abstractLinkableparent, ...) carries@Introspectedonly - none of them are@Serdeableor registered via@SerdeImport. Micronaut Serde correctly rejects@Introspected-only classes at runtime; Micronaut Jackson Databind serialises them via Jackson + bean introspection. The mismatch turns every JSON endpoint behindnext.grails.organdprev-snapshot.grails.orginto a 500.The other Forge modules -
forge-apitests,forge-core,analytics-postgres- all still usemicronaut-jackson-databind;web-nettywas the only inconsistency.Fix
Restore
runtimeOnly 'io.micronaut:micronaut-jackson-databind'ingrails-forge-web-netty/build.gradleso the JSON runtime matches the rest of the forge stack and the existing@IntrospectedDTOs serialise. A proper end-to-end Serde migration belongs in a separate PR that also annotates every Forge DTO with@Serdeable/@SerdeImportat the same time.Verification
Reproduced locally on Docker 29.3.0 with the same Java 21 GraalVM Community 21.0.2-ol9 native-image container the deploy workflows use, then rebuilt with the fix:
Endpoints serve JSON cleanly with the CORS allow-origin header. Once
next.grails.organdprev-snapshot.grails.orgare redeployed from this commit, the start.grails.org Grails Version selector will pick up 8.0.0-M1 and 8.0-SNAPSHOT.