SupportAutoType 在 @type 不是首个字段时无法反序列化为目标类型
- 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
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