Skip to content

fix: ClassFormatError when generating writers for array-typed fields (#4009) - #4014

Merged
wenshao merged 1 commit into
mainfrom
fix/issue-4009-classformaterror
Aug 2, 2026
Merged

fix: ClassFormatError when generating writers for array-typed fields (#4009)#4014
wenshao merged 1 commit into
mainfrom
fix/issue-4009-classformaterror

Conversation

@wenshao

@wenshao wenshao commented Mar 10, 2026

Copy link
Copy Markdown
Member

Problem

JSON.toJSON(bean) throws ClassFormatError when the bean has an array-typed field:

public class BeanWithClassArray {
    private String name;
    private Class<?>[] classes;
    // getters / setters
}

JSON.toJSON(bean);
java.lang.ClassFormatError: Illegal class name "com/alibaba/fastjson2/writer/OWG_5_0_Class[]"
        in class file com/alibaba/fastjson2/writer/OWG_5_0_Class[]

Root cause

ObjectWriterCreatorASM embeds objectClass.getSimpleName() in the name of the class it generates:

String className = "OWG_" + seed.incrementAndGet() + "_" + fieldWriters.size()
        + (objectClass == null ? "" : ("_" + objectClass.getSimpleName()));

For an array type the simple name ends in []Class[] — and [ is not legal in a class name, so defineClass rejects the generated bytes.

Fix

Sanitize the simple name before embedding it: array notation becomes a suffix (Class[]ClassArray), and any other character that is not valid in a class name becomes an underscore.

The helper lives in com.alibaba.fastjson2.internal.asm.ASMUtils, which both ObjectWriterCreatorASM and ObjectReaderCreatorASM already static-import, so the two cannot drift apart:

public static String sanitizeClassName(String simpleName)

Scope

The writer is the only path that could produce an illegal name. The reader call sites are defensive symmetry, verified rather than assumed:

reader(Class[]) -> com.alibaba.fastjson2.reader.ObjectReaderAdapter
writer(Class[]) -> com.alibaba.fastjson2.writer.OWG_1_0_ClassArray

ObjectReaderCreatorASM never generates a class for an array type — it returns ObjectReaderAdapter, so the ORG_ path is not reached. Its other call site (VBACG_/VCACG_ in createValueConsumer0) bails out earlier still, since it requires a default constructor and a public class, and an array type has neither.

Tests

  • Issue4009Test — serialization and round-trip for Class[] and int[][] fields.
  • ASMUtilsTest — unit coverage for sanitizeClassName: null/empty, unchanged names, arrays including int[][], special characters, and the combined My$Class[].

Verification

Revert-probe — removing sanitizeClassName from ObjectWriterCreatorASM makes the integration test fail with the exact error from #4009:

[ERROR] Issue4009Test.testClassArrayField
        java.lang.ClassFormatError: Illegal class name "com/alibaba/fastjson2/writer/OWG_2_0_Class[]"

Full suites green locally on JDK 26 — core 7965, extension 56, fastjson1-compatible 1355, kotlin 36, safemode-test 2 — and core again with -Dfastjson2.creator=reflect.

Closes #4009

中文说明

问题

Bean 中含有数组类型字段时,JSON.toJSON(bean)ClassFormatError

public class BeanWithClassArray {
    private String name;
    private Class<?>[] classes;
    // getters / setters
}

JSON.toJSON(bean);
java.lang.ClassFormatError: Illegal class name "com/alibaba/fastjson2/writer/OWG_5_0_Class[]"
        in class file com/alibaba/fastjson2/writer/OWG_5_0_Class[]

根因

ObjectWriterCreatorASM 会把 objectClass.getSimpleName() 拼进它生成的类名:

String className = "OWG_" + seed.incrementAndGet() + "_" + fieldWriters.size()
        + (objectClass == null ? "" : ("_" + objectClass.getSimpleName()));

数组类型的 simple name 以 [] 结尾(Class[]),而 [ 在类名中非法,defineClass 因此拒绝生成的字节码。

修复

拼接前先对 simple name 做净化:数组记法转成后缀(Class[]ClassArray),其余在类名中非法的字符替换为下划线。

方法放在 com.alibaba.fastjson2.internal.asm.ASMUtils —— ObjectWriterCreatorASMObjectReaderCreatorASM 本来就 static import 了它,两边不会各自演化:

public static String sanitizeClassName(String simpleName)

影响范围

只有 writer 会产生非法类名。reader 那两处是防御性对称,这一点是实测确认的,不是推断:

reader(Class[]) -> com.alibaba.fastjson2.reader.ObjectReaderAdapter
writer(Class[]) -> com.alibaba.fastjson2.writer.OWG_1_0_ClassArray

ObjectReaderCreatorASM 对数组类型根本不生成类,直接返回 ObjectReaderAdapter,走不到 ORG_ 路径。另一处(createValueConsumer0 里的 VBACG_/VCACG_)退出得更早:它要求有默认构造器且类是 public,数组类型两条都不满足。

测试

  • Issue4009Test —— Class[]int[][] 字段的序列化及 round-trip。
  • ASMUtilsTest —— sanitizeClassName 的单测:null/空、无需改写的名字、数组(含 int[][])、特殊字符,以及组合场景 My$Class[]

验证

Revert-probe:把 sanitizeClassNameObjectWriterCreatorASM 移除后,集成测试以 #4009 中一模一样的错误失败:

[ERROR] Issue4009Test.testClassArrayField
        java.lang.ClassFormatError: Illegal class name "com/alibaba/fastjson2/writer/OWG_2_0_Class[]"

本地 JDK 26 全量通过 —— core 7965、extension 56、fastjson1-compatible 1355、kotlin 36、safemode-test 2;-Dfastjson2.creator=reflect 下 core 同样通过。

@wenshao

wenshao commented Apr 25, 2026

Copy link
Copy Markdown
Member Author

No issues found. LGTM! ✅ — gpt-5.5 via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

— qwen3.8-max-preview via Qwen Code /review

Comment thread core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterCreatorASM.java Outdated
…s, for issue #4009

When calling JSON.toJSON() on an object with a Class[] (or any array-typed)
field, the ASM writer generated class names like "OWG_5_0_Class[]", which are
illegal Java class names, so defineClass threw ClassFormatError.

Sanitize the simple name embedded in generated class names: array notation
becomes a suffix ("Class[]" -> "ClassArray") and any other character invalid in
a class name becomes an underscore.

sanitizeClassName lives in ASMUtils, which both creators already static-import,
so the writer and reader cannot drift apart.
@wenshao
wenshao force-pushed the fix/issue-4009-classformaterror branch from 64e769a to 272d1ca Compare August 2, 2026 08:29
@wenshao wenshao changed the title fix: ClassFormatError when serializing classes with array-typed field… fix: ClassFormatError when generating writers for array-typed fields (#4009) Aug 2, 2026
@wenshao
wenshao merged commit 6b40188 into main Aug 2, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 升级到fastjson 2.0.57报错

1 participant