-
Notifications
You must be signed in to change notification settings - Fork 6.5k
对泛型的具化衍生类支持有问题 #3730
Comments
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
奇怪的是,非inner public static class居然 |
没错,也是fastjson才会有的报错 |
给一个workaround,可以绕过这个问题 package com.ayanamist;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
Derived d = new Derived();
d.put("k", Collections.singletonList(new DAO()));
String str = com.alibaba.fastjson.JSON.toJSONString(d);
System.out.printf("Str: %s\n", str);
com.google.gson.Gson gson = new com.google.gson.Gson();
d = gson.fromJson(str, Derived.class);
System.out.printf(Locale.ENGLISH, "gson: %s\n", d.get("k").get(0).getClass().getSimpleName());
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
d = objectMapper.readValue(str, Derived.class);
System.out.printf(Locale.ENGLISH, "jackson: %s\n", d.get("k").get(0).getClass().getSimpleName());
// workaround https://github.com/alibaba/fastjson/issues/3730
ParserConfig.getGlobalInstance().putDeserializer(Derived.class, DerivedDeserializer.instance);
d = com.alibaba.fastjson.JSON.parseObject(str, Derived.class);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").get(0).getClass().getSimpleName());
}
public static class DAO {
private String aaa = "ccc";
private int bbb = 2;
public String getAaa() {
return aaa;
}
public void setAaa(String aaa) {
this.aaa = aaa;
}
public int getBbb() {
return bbb;
}
public void setBbb(int bbb) {
this.bbb = bbb;
}
}
// @JSONType(deserializer = DerivedDeserializer.class) is useless, since com.alibaba.fastjson.parser.ParserConfig.getDeserializer will use MapDeserializer first
public static class Derived extends HashMap<String, List<DAO>> {
public Derived() {
super();
}
public Derived(Map<String, List<DAO>> object) {
super(object);
}
}
public static class DerivedDeserializer implements ObjectDeserializer {
public static final DerivedDeserializer instance = new DerivedDeserializer();
private static final TypeReference<HashMap<String, List<DAO>>> TYPE_REFERENCE = new TypeReference<HashMap<String, List<DAO>>>() {
};
@SuppressWarnings("unchecked")
@Override public Derived deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
return new Derived(parser.parseObject(TYPE_REFERENCE.getType()));
}
@Override public int getFastMatchToken() {
return JSONToken.LBRACE;
}
}
} |
跟了一下代码,问题出在 package com.ayanamist;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.MapDeserializer;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
Derived d = new Derived();
d.put("k", Collections.singletonList(new DAO()));
String str = com.alibaba.fastjson.JSON.toJSONString(d);
System.out.printf("Str: %s\n", str);
com.google.gson.Gson gson = new com.google.gson.Gson();
d = gson.fromJson(str, Derived.class);
System.out.printf(Locale.ENGLISH, "gson: %s\n", d.get("k").get(0).getClass().getSimpleName());
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
d = objectMapper.readValue(str, Derived.class);
System.out.printf(Locale.ENGLISH, "jackson: %s\n", d.get("k").get(0).getClass().getSimpleName());
// workaround https://github.com/alibaba/fastjson/issues/3730
ParserConfig.getGlobalInstance().putDeserializer(Derived.class, GenericMapSuperclassDeserializer.instance);
d = com.alibaba.fastjson.JSON.parseObject(str, Derived.class);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").get(0).getClass().getSimpleName());
}
public static class DAO {
private String aaa = "ccc";
private int bbb = 2;
public String getAaa() {
return aaa;
}
public void setAaa(String aaa) {
this.aaa = aaa;
}
public int getBbb() {
return bbb;
}
public void setBbb(int bbb) {
this.bbb = bbb;
}
}
// @JSONType(deserializer = DerivedDeserializer.class) is useless, since com.alibaba.fastjson.parser.ParserConfig.getDeserializer will use MapDeserializer first
public static class Derived extends HashMap<String, List<DAO>> {
}
private static class GenericMapSuperclassDeserializer implements ObjectDeserializer {
public static final GenericMapSuperclassDeserializer instance = new GenericMapSuperclassDeserializer();
@SuppressWarnings("unchecked")
@Override public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
Class<?> clz = (Class<?>) type;
Type genericSuperclass = clz.getGenericSuperclass();
Map map;
try {
map = (Map) clz.newInstance();
} catch (Exception e) {
throw new JSONException("unsupport type " + type, e);
}
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type keyType = parameterizedType.getActualTypeArguments()[0];
Type valueType = parameterizedType.getActualTypeArguments()[1];
if (String.class == keyType) {
return (T) MapDeserializer.parseMap(parser, (Map<String, Object>) map, valueType, fieldName, 0);
} else {
return (T) MapDeserializer.parseMap(parser, map, keyType, valueType, fieldName);
}
}
@Override public int getFastMatchToken() {
return JSONToken.LBRACE;
}
}
} |
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
这个应该是一个feature。在 #3448 #1583 中提到过相似的问题,已经被修复。在map类型的反序列化中,如果value是list类型(用“[”括起),在结果对象中的value会是JSONArray类型。需要用户自己做后续工作。 import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class test {
public static void main(String[] args) throws Exception {
Derived d = new Derived();
d.put("k", Collections.singletonList(new DAO()));
String str = com.alibaba.fastjson.JSON.toJSONString(d);
System.out.printf("Str: %s\n", str);
d = com.alibaba.fastjson.JSON.parseObject(str, Derived.class);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").getClass().getSimpleName());
Object data = d.get("k");
List<DAO> list = null;
list = JSONObject.parseArray(((JSONArray) data).toJSONString(), DAO.class);
assert list != null;
System.out.println(list.get(0).getClass().getSimpleName());
}
public static class DAO {
private String aaa = "ccc";
private int bbb = 2;
public String getAaa() {
return aaa;
}
public void setAaa(String aaa) {
this.aaa = aaa;
}
public int getBbb() {
return bbb;
}
public void setBbb(int bbb) {
this.bbb = bbb;
}
}
public static class Derived extends HashMap<String, List<DAO>> {
}
} 结果是
|
我说的不是JsonArray的事情,是array里面不是要的对象,而是JsonObject,而传过去的对象类型明明已经明确了具体的类。 |
package com.alibaba.json.bvt.issue_3700;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class Issue3730_3 {
private static final String test_str = "{\"k\":{\"aaa\":\"ccc\",\"bbb\":2}}";
private static final String test_str2 = "{\"k\":[{\"aaa\":\"ccc\",\"bbb\":2}]}";
@Test
public void test_for_issue_parse_output_PublicstaticKV_1() {
Issue3730_2DerivedPublicStaticKV d = parseToMap(test_str, String.class, Issue3730_2DAOPublicStatic.class);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").getClass().getSimpleName());
}
@Test
public void test_for_issue_parse_output_Publicstatic_KV2() {
Issue3730_2DerivedPublicStaticKV2 d = parseToMap2(test_str2, String.class, Issue3730_2DAOPublicStatic.class);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").getClass().getSimpleName());
}
@Test
public void test_for_issue_parse_output_Publicstatic_KV2_warp() {
Issue3730_2DerivedPublicStaticKV2<String, Issue3730_2DAOPublicStatic> d = parseToMap2_warp(test_str2);
System.out.printf(Locale.ENGLISH, "fastjson: %s\n", d.get("k").getClass().getSimpleName());
}
public static <K, V> Issue3730_2DerivedPublicStaticKV<K, V> parseToMap(String json,
Class<K> keyType,
Class<V> valueType) {
return JSON.parseObject(json,
new TypeReference<Issue3730_2DerivedPublicStaticKV<K, V>>(keyType, valueType) {
}.getType());
}
public static <K, V> Issue3730_2DerivedPublicStaticKV2<String, Issue3730_2DAOPublicStatic> parseToMap2_warp(String json) {
return JSON.parseObject(json,
new TypeReference<Issue3730_2DerivedPublicStaticKV2<K, List<V>>>(String.class, Issue3730_2DAOPublicStatic.class) {
}.getType());
}
public static <K, V> Issue3730_2DerivedPublicStaticKV2<K, V> parseToMap2(String json,
Class<K> keyType,
Class<V> valueType) {
return JSON.parseObject(json,
new TypeReference<Issue3730_2DerivedPublicStaticKV2<K, List<V>>>(keyType, valueType) {
}.getType());
}
public static class Issue3730_2DAOPublicStatic {
private String aaa = "ccc";
private int bbb = 2;
public String getAaa() {
return aaa;
}
public void setAaa(String aaa) {
this.aaa = aaa;
}
public int getBbb() {
return bbb;
}
public void setBbb(int bbb) {
this.bbb = bbb;
}
}
public static class Issue3730_2DerivedPublicStaticKV<K, V> extends HashMap<K, V> {
}
public static class Issue3730_2DerivedPublicStaticKV2<K, V> extends HashMap<K, List<V>> {
}
} 感觉关键在于给的类型信息太少了,参考wiki-typereference写出来的就可以 |
和 #1097 看起来很相似 |
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
</subject> Branch: issue3730 <type>: - [ ] Bug fix - [ ] Bug fix (Test) - [ ] New feature - [ ] Breaking change - [ ] Documentation update - [ ] This change requires a documentation update <body> <footer> Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
和gson、jackson的对比如下代码。
输出结果:
可以看到gson和jackson都能正确的反序列化这个类,但fastjson却反序列化成了JSONObject,导致抛出异常
The text was updated successfully, but these errors were encountered: