Problem
The Java runtime ships a metadata-driven JSON layer for MetaObject-backed instances, but none of the generated agent guidance mentions it exists. A consumer (or a coding agent following the shipped skills) hits a serialization failure on a generated VO, finds no guidance, and hand-rolls a Jackson workaround — reimplementing, badly, something the jar already provides.
That happened to us this week, twice, on the same codebase.
What exists but is undocumented
Present in metaobjects-metadata 7.20.11 and metaobjects-codegen-base 7.20.11:
| class |
what it is |
com.metaobjects.io.object.json.JsonObjectWriter / JsonObjectReader |
metadata-driven object JSON read/write |
com.metaobjects.io.object.gson.MetaObjectSerializer |
Gson serializer for MetaObject-backed instances |
com.metaobjects.object.MetaObjectAware |
the interface that makes an instance metadata-aware |
com.metaobjects.generator.direct.object.javacode.PojoAwareCodeWriter |
codegen emitting plain POJOs that implement MetaObjectAware |
The documentation gap
Across the generated agent context for a java, kotlin server, react, tanstack project:
.metaobjects/AGENTS.md and .metaobjects/CLAUDE.md — 0 mentions of any of the above
- every
metaobjects-* skill, including metaobjects-codegen/references/java.md and metaobjects-runtime-ui/references/java.md — 0 mentions
metaobjects-codegen/references/java.md has a generator table listing SpringControllerGenerator, SpringDtoGenerator, SpringRepositoryGenerator, SpringPayloadGenerator, SpringOutputParserGenerator, SpringFilterAllowlistGenerator — but not PojoAwareCodeWriter, and nothing anywhere says how a generated object should be serialized.
Why the gap bites specifically
Extract-route VOs extend PojoObject, whose framework field is a MetaObject back-reference. A default Jackson ObjectMapper walking that reference fails with InaccessibleObjectException under JPMS. The failure surfaces at the consumer's serialization call, far from any metadata concept, so the natural (wrong) reaction is to treat it as a Jackson problem:
- Two of our services shipped with the response-VO capture disabled entirely, each carrying a comment saying the parsed views "carry MetaObjects framework internals" and could not be serialized — i.e. a real feature was switched off because the supported path was undiscoverable.
- The eventual "fix" was a hand-written
@JsonIgnoreType mixin on MetaObject plus FIELD visibility and FAIL_ON_EMPTY_BEANS=false. It works, and it should never have been written.
Both are consumer-side symptoms of one missing paragraph.
Suggested fix
- A serialization section in
references/java.md (and the equivalent per-port fragment): when you have a MetaObject-backed instance and need JSON, use JsonObjectWriter/MetaObjectSerializer — with a snippet. State explicitly that a default Jackson/Gson mapper over a PojoObject subtype will fail on the MetaObject back-reference, and that this is expected rather than a bug to work around.
- List
PojoAwareCodeWriter in the generator table, and say when to choose POJO+MetaObjectAware output over PojoObject — a plain POJO that is metadata-aware serializes with an ordinary mapper, which is the simpler answer for consumers who mostly want normal Jackson behaviour.
- One line in
AGENTS.md under the principles, in the same spirit as "use the generated constants for any string that names metadata": serialize generated objects through the MetaObjects JSON layer, don't hand-configure a mapper around the framework fields.
- Optionally a
metaobjects-verify / adoption-audit check that flags a hand-configured ObjectMapper touching generated types.
Context
Found while adding per-call telemetry capture in a Java/Kotlin consumer on metaobjects 7.20.11. Happy to contribute the references/java.md section if the shape above looks right.
Problem
The Java runtime ships a metadata-driven JSON layer for MetaObject-backed instances, but none of the generated agent guidance mentions it exists. A consumer (or a coding agent following the shipped skills) hits a serialization failure on a generated VO, finds no guidance, and hand-rolls a Jackson workaround — reimplementing, badly, something the jar already provides.
That happened to us this week, twice, on the same codebase.
What exists but is undocumented
Present in
metaobjects-metadata7.20.11 andmetaobjects-codegen-base7.20.11:com.metaobjects.io.object.json.JsonObjectWriter/JsonObjectReadercom.metaobjects.io.object.gson.MetaObjectSerializercom.metaobjects.object.MetaObjectAwarecom.metaobjects.generator.direct.object.javacode.PojoAwareCodeWriterMetaObjectAwareThe documentation gap
Across the generated agent context for a
java, kotlin server, react, tanstackproject:.metaobjects/AGENTS.mdand.metaobjects/CLAUDE.md— 0 mentions of any of the abovemetaobjects-*skill, includingmetaobjects-codegen/references/java.mdandmetaobjects-runtime-ui/references/java.md— 0 mentionsmetaobjects-codegen/references/java.mdhas a generator table listingSpringControllerGenerator,SpringDtoGenerator,SpringRepositoryGenerator,SpringPayloadGenerator,SpringOutputParserGenerator,SpringFilterAllowlistGenerator— but notPojoAwareCodeWriter, and nothing anywhere says how a generated object should be serialized.Why the gap bites specifically
Extract-route VOs extend
PojoObject, whose framework field is aMetaObjectback-reference. A default JacksonObjectMapperwalking that reference fails withInaccessibleObjectExceptionunder JPMS. The failure surfaces at the consumer's serialization call, far from any metadata concept, so the natural (wrong) reaction is to treat it as a Jackson problem:@JsonIgnoreTypemixin onMetaObjectplusFIELDvisibility andFAIL_ON_EMPTY_BEANS=false. It works, and it should never have been written.Both are consumer-side symptoms of one missing paragraph.
Suggested fix
references/java.md(and the equivalent per-port fragment): when you have a MetaObject-backed instance and need JSON, useJsonObjectWriter/MetaObjectSerializer— with a snippet. State explicitly that a default Jackson/Gson mapper over aPojoObjectsubtype will fail on theMetaObjectback-reference, and that this is expected rather than a bug to work around.PojoAwareCodeWriterin the generator table, and say when to choose POJO+MetaObjectAwareoutput overPojoObject— a plain POJO that is metadata-aware serializes with an ordinary mapper, which is the simpler answer for consumers who mostly want normal Jackson behaviour.AGENTS.mdunder the principles, in the same spirit as "use the generated constants for any string that names metadata": serialize generated objects through the MetaObjects JSON layer, don't hand-configure a mapper around the framework fields.metaobjects-verify/ adoption-audit check that flags a hand-configuredObjectMappertouching generated types.Context
Found while adding per-call telemetry capture in a Java/Kotlin consumer on metaobjects 7.20.11. Happy to contribute the
references/java.mdsection if the shape above looks right.