Skip to content

Commit 14ea6ea

Browse files
wenshaoclaude
andauthored
fix: Map subclass loses @type when serialized with ValueFilter (#3984) (#4029)
* fix: Map subclass loses @type when serialized with ValueFilter (#3984) ObjectWriterImplMap.writeWithFilter() was missing the writeTypeInfo call that write() had, causing @type to be silently dropped when any filter was present with WriteClassName enabled. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: use exact class name and occurrence count in assertions Address review feedback: assert against full qualified type name via CustomMap.class.getName() and count exact @type occurrences instead of substring checks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: use structural JSON assertions instead of substring matching Parse serialized JSON and assert @type via JSONObject.getString() rather than substring matching, making tests resilient to formatting/order changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ede10a5 commit 14ea6ea

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

core/src/main/java/com/alibaba/fastjson2/writer/ObjectWriterImplMap.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,12 @@ public void writeWithFilter(JSONWriter jsonWriter, Object object, Object fieldNa
617617
jsonWriter.startObject();
618618
Map map = (Map) object;
619619

620+
boolean writeTypeInfo = (fieldType == this.objectType && jsonWriter.isWriteMapTypeInfo(object, this.objectClass, features))
621+
|| jsonWriter.isWriteTypeInfo(object, fieldType, features);
622+
if (writeTypeInfo) {
623+
writeTypeInfo(jsonWriter);
624+
}
625+
620626
features |= jsonWriter.getFeatures();
621627
if ((features & (MapSortField.mask | SortMapEntriesByKeys.mask)) != 0) {
622628
if (!(map instanceof SortedMap)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.alibaba.fastjson2.issues_3900;
2+
3+
import com.alibaba.fastjson2.JSON;
4+
import com.alibaba.fastjson2.JSONObject;
5+
import com.alibaba.fastjson2.JSONWriter;
6+
import com.alibaba.fastjson2.filter.ValueFilter;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.util.HashMap;
10+
11+
import static org.junit.jupiter.api.Assertions.assertEquals;
12+
13+
public class Issue3984 {
14+
static final String CUSTOM_MAP_TYPE = CustomMap.class.getName();
15+
16+
public static class CustomMap extends HashMap<String, Object> {
17+
}
18+
19+
@Test
20+
public void testWriteClassNameWithValueFilter() {
21+
CustomMap map = new CustomMap();
22+
map.put("key1", "value1");
23+
24+
ValueFilter valueFilter = (object, name, value) -> value;
25+
26+
String json = JSON.toJSONString(map,
27+
new ValueFilter[]{valueFilter},
28+
JSONWriter.Feature.WriteClassName);
29+
30+
JSONObject parsed = JSON.parseObject(json);
31+
assertEquals(CUSTOM_MAP_TYPE, parsed.getString("@type"));
32+
assertEquals("value1", parsed.getString("key1"));
33+
}
34+
35+
@Test
36+
public void testWriteClassNameWithoutFilter() {
37+
CustomMap map = new CustomMap();
38+
map.put("key1", "value1");
39+
40+
String json = JSON.toJSONString(map, JSONWriter.Feature.WriteClassName);
41+
42+
JSONObject parsed = JSON.parseObject(json);
43+
assertEquals(CUSTOM_MAP_TYPE, parsed.getString("@type"));
44+
assertEquals("value1", parsed.getString("key1"));
45+
}
46+
47+
@Test
48+
public void testNestedMapWithValueFilter() {
49+
CustomMap inner = new CustomMap();
50+
inner.put("msg", 123);
51+
52+
CustomMap outer = new CustomMap();
53+
outer.put("key1", "value1");
54+
outer.put("nested", inner);
55+
56+
ValueFilter valueFilter = (object, name, value) -> value;
57+
58+
String json = JSON.toJSONString(outer,
59+
new ValueFilter[]{valueFilter},
60+
JSONWriter.Feature.WriteClassName);
61+
62+
JSONObject parsed = JSON.parseObject(json);
63+
assertEquals(CUSTOM_MAP_TYPE, parsed.getString("@type"));
64+
assertEquals("value1", parsed.getString("key1"));
65+
66+
JSONObject nestedParsed = parsed.getJSONObject("nested");
67+
assertEquals(CUSTOM_MAP_TYPE, nestedParsed.getString("@type"));
68+
assertEquals(123, nestedParsed.getIntValue("msg"));
69+
}
70+
}

0 commit comments

Comments
 (0)