fix: add null guard for writeEnum and enumCapacity in JSONB.IO (#7806) - #7831
fix: add null guard for writeEnum and enumCapacity in JSONB.IO (#7806)#7831waterWang wants to merge 1 commit into
Conversation
…ba#7806) When JSONB.toBytes is called with WriteNulls enabled on an object whose enum field is null, the ASM-generated ObjectWriter (OWG) directly calls JSONB.IO.writeEnum(byte[], int, Enum, long), which did not handle null e — accessing e.ordinal() threw NullPointerException. The same issue affects JSONB.IO.enumCapacity which is called during buffer pre-allocation. Fix by adding early null checks in both methods: - writeEnum: write BC_NULL (1 byte) when e is null - enumCapacity: return 1 (BC_NULL size) when e is null FieldWriterEnum.writeEnumValueJSONB already had the same null guard (writes BC_NULL), but the ASM-generated fast path bypassed it when symbolTable is null. Closes alibaba#7806
|
|
wenshao
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
— gpt-5.6-sol@954e5164 via Qwen Code /review (v0.22.0)
| if (e == null) { | ||
| return 1; | ||
| } |
There was a problem hiding this comment.
[Suggestion] Add a regression test for the ASM null-enum JSONB path
This fixes the production path, but no test pins the generated OWG_* direct writer that triggered issue 7806. A later refactor could remove or bypass either guard and JSONB.toBytes(bean, WriteNulls, WriteClassName) would again throw while the current suite remains green.
An isolated probe confirmed the generated writer was OWG_1_1_Bean; removing the writeEnum guard produced:
java.lang.NullPointerException: Cannot invoke "java.lang.Enum.ordinal()" because "e" is null
at com.alibaba.fastjson2.JSONB$IO.writeEnum(JSONB.java:2199)
at com.alibaba.fastjson2.writer.OWG_1_1_Bean.writeJSONB(Unknown Source)
Please add an Issue7806 regression test with a null enum field through the ASM writer, asserting WriteNulls + WriteClassName preserves null and a non-null value remains unchanged. Add a WriteEnumsUsingName or WriteEnumUsingToString variant to independently pin enumCapacity's guard. The test must fail when the writeEnum guard is removed, and the enum-name/toString variant must fail when the enumCapacity guard is removed.
— gpt-5.6-sol@954e5164 via Qwen Code /review (v0.22.0)
Summary
Fixes #7806: NPE when serializing an object with a null enum field via
JSONB.toByteswithWriteNulls(andWriteClassName).Root cause
When
JSONB.toBytes(obj, WriteNulls, ...)runs on a class with an enum field whose value isnull, the ASM-generatedObjectWriter(classOWG_*) serializes the field throughJSONB.IO.writeEnum(byte[], int, Enum, long)directly. That method had no null guard — withe == nullit accessede.ordinal()and threwNullPointerException.The companion
JSONB.IO.enumCapacity(used for buffer pre-allocation) had the same missing guard.FieldWriterEnum.writeEnumValueJSONBalready handled null correctly (writesBC_NULL), but the ASM fast path bypassed it whensymbolTableis null.Fix
Add early null checks to both methods in
JSONB.IO:writeEnum: writeBC_NULL(1 byte) wheneis null, returnoff + 1enumCapacity: return1(theBC_NULLsize) wheneis nullThis matches the existing null handling in
FieldWriterEnum.writeEnumValueJSONBandJSONWriter.writeEnum.Verification
Reproduced the exact stack trace on
main, then confirmed the fix:WriteNulls+WriteClassName→ serializescolor:null(previously NPE)One file changed (+7). No functional change for non-null enum values.