You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by ja...@apache.org on 2026/05/08 22:02:33 UTC
(grails-core) branch hotfix/forge-native-image-8.0.0-M1 updated: Restore micronaut-jackson-databind for grails-forge-web-netty JSON runtime
This is an automated email from the ASF dual-hosted git repository.
jamesfredley pushed a commit to branch hotfix/forge-native-image-8.0.0-M1
in repository https://gitbox.apache.org/repos/asf/grails-core.git
The following commit(s) were added to refs/heads/hotfix/forge-native-image-8.0.0-M1 by this push:
new 0363e145e2 Restore micronaut-jackson-databind for grails-forge-web-netty JSON runtime
0363e145e2 is described below
commit 0363e145e29472ec039a436fd08cbddf7663add0
Author: James Fredley <ja...@users.noreply.github.com>
AuthorDate: Fri May 8 18:00:49 2026 -0400
Restore micronaut-jackson-databind for grails-forge-web-netty JSON runtime
After PR #15647 + #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 #15365 review feedback (commit e1f3013070,
"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
---
grails-forge/grails-forge-web-netty/build.gradle | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/grails-forge/grails-forge-web-netty/build.gradle b/grails-forge/grails-forge-web-netty/build.gradle
index 2f697cae65..6fc01b0263 100644
--- a/grails-forge/grails-forge-web-netty/build.gradle
+++ b/grails-forge/grails-forge-web-netty/build.gradle
@@ -32,7 +32,20 @@ dependencies {
implementation 'io.micronaut.gcp:micronaut-gcp-http-client'
runtimeOnly 'ch.qos.logback:logback-classic'
- runtimeOnly 'io.micronaut.serde:micronaut-serde-jackson'
+ // Forge's grails-forge-api DTO classes (VersionDTO, ApplicationTypeDTO,
+ // FeatureDTO, SelectOptionsDTO, Linkable, ...) are annotated with
+ // @Introspected only. micronaut-serde-jackson requires @Serdeable on
+ // each serializable type and rejects @Introspected-only classes at
+ // runtime, which surfaces in the deployed native image as
+ // "Internal Server Error: Error encoding object [VersionDTO@..] to
+ // JSON: No serializable introspection present for type VersionDTO."
+ // and breaks every JSON endpoint behind start.grails.org / next.grails.org
+ // / 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.
+ runtimeOnly 'io.micronaut:micronaut-jackson-databind'
testImplementation 'io.micronaut:micronaut-http-client'
testImplementation 'io.micronaut.test:micronaut-test-spock'