alibaba / alibaba/fastjson2

SupportAutoType 在 @type 不是首个字段时无法反序列化为目标类型

Open
#7,639 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Java
Stars
4.4k
Forks
613
Avg merge
1d 22h
Merged PRs (30d)
6

Description

## 问题描述

使用 Fastjson2 反序列化时,如果通过 `Object.class + JSONReader.Feature.SupportAutoType` 依赖 JSON 中的 `@type` 字段进行 AutoType 类型识别,那么只有当 `@type` 位于 JSON 对象首位时,才能正常反序列化为目标 JavaBean。

如果 `@type` 不在首位,例如位于 `id` 字段之后,Fastjson2 实际返回的是 `com.alibaba.fastjson2.JSONObject`,而不是 `@type` 指定的目标类型。业务代码后续强转时会抛出 `ClassCastException`。

## 环境信息

请根据实际环境替换以下内容:

- fastjson2 版本:`2.0.xx`
- JDK 版本:`17 / 21`
- 操作系统:`Windows / macOS / Linux`
- 测试框架:`JUnit 5`

## 最小复现代码

```java
package com.example;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
* Fastjson2 AutoType 字段顺序测试
*
* @author Ateng
* @since 2026-05-09
*/
class Fastjson2AutoTypeIssueTest {

@Test
void supportAutoTypeWhenTypeFieldIsFirst() {
AutoType1 entity = new AutoType1(1L, "ateng");

String json = JSON.toJSONString(entity, JSONWriter.Feature.WriteClassName);
System.out.println(json);

Object object = JSON.parseObject(json, Object.class, JSONReader.Feature.SupportAutoType);

System.out.println(object.getClass());
System.out.println(object);

Assertions.assertInstanceOf(AutoType1.class, object);
}

@Test
void supportAutoTypeWhenTypeFieldIsNotFirst() {
String typeName = AutoType1.class.getName();

String json = "{\"id\":1,\"@type\":\"" + typeName + "\",\"name\":\"ateng\"}";
System.out.println(json);

Object object = JSON.parseObject(json, Object.class, JSONReader.Feature.SupportAutoType);

System.out.println(object.getClass());
System.out.println(object);

Assertions.assertInstanceOf(AutoType1.class, object);
}

/**
* AutoType 测试实体
*
* @author Ateng
* @since 2026-05-09
*/
public static class AutoType1 {

private Long id;

private String name;

public AutoType1() {
}

public AutoType1(Long id, String name) {
this.id = id;
this.name = name;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "AutoType1{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
}
```

## 当前行为

当 `@type` 是 JSON 对象的首个字段时,可以正常反序列化为目标类型。

示例 JSON:

```json
{
"@type": "com.example.Fastjson2AutoTypeIssueTest$AutoType1",
"id": 1,
"name": "ateng"
}
```

实际结果:

```text
class com.example.Fastjson2AutoTypeIssueTest$AutoType1
```

但是当 `@type` 不是首个字段时:

```json
{
"id": 1,
"@type": "com.example.Fastjson2AutoTypeIssueTest$AutoType1",
"name": "ateng"
}
```

实际结果变成:

```text
class com.alibaba.fastjson2.JSONObject
```

如果业务代码中直接强转:

```java
AutoType1 entity = (AutoType1) JSON.parseObject(json, Object.class, JSONReader.Feature.SupportAutoType);
```

会抛出异常:

```text
java.lang.ClassCastException: class com.alibaba.fastjson2.JSONObject cannot be cast to class com.example.Fastjson2AutoTypeIssueTest$AutoType1
```

## 期望行为

开启 `JSONReader.Feature.SupportAutoType` 后,如果 JSON 对象中存在合法的 `@type` 字段,并且类型允许被反序列化,希望 Fastjson2 能根据 `@type` 反序列化为目标类型,而不是依赖 `@type` 必须出现在首位。

下面两个 JSON 期望表现一致:

```json
{
"@type": "com.example.Fastjson2AutoTypeIssueTest$AutoType1",
"id": 1,
"name": "ateng"
}
```

```json
{
"id": 1,
"@type": "com.example.Fastjson2AutoTypeIssueTest$AutoType1",
"name": "ateng"
}
```

## 影响场景

这个问题在 JSON 字段顺序无法保证的场景中比较容易出现,例如:

1. JSON 不是由 Fastjson2 直接序列化生成,而是由其他系统生成。
2. JSON 存储在 Redis、数据库、MQ 或配置中心。
3. 中间系统、网关、消息队列或存储系统可能调整 JSON 字段顺序。
4. 业务代码使用 `Object.class + SupportAutoType` 恢复多态对象。
5. `@type` 可能无法保证始终位于 JSON 对象首位。

## 疑问

请问这是 Fastjson2 当前的预期行为吗?

如果 `Object.class + SupportAutoType` 场景下要求 `@type` 必须是 JSON 对象的首个字段,是否可以在文档中明确说明这个限制?

如果这不是预期行为,是否可以支持 `@type` 出现在对象字段的任意位置时,也能正常识别并反序列化为目标类型?

Contributor guide

Open the contributing guide

Research direction

Start with the minimal reproduction in Fastjson2AutoTypeIssueTest and run both tests using JSON.parseObject with Object.class and JSONReader.Feature.SupportAutoType. Trace the auto-type handling from that entry point for objects where @type is first or follows id. Done means both field orders deserialize to AutoType1 and the assertions pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.