fastjson2
fastjson2 copied to clipboard
[BUG] 反序列化 LinkedMultiValueMap时Array 变成了 JSONArray
问题描述
我在接口请求数据 JSON.parseObject(respJson, LinkedMultiValueMap) 发现数据类型不一致,导致我后续的removeif出错
环境信息
请填写以下信息:
- OS信息: windows
- JDK信息:azul-17.0.10
- 版本信息:Fastjson2.0.47
重现步骤
如何操作可以重现该问题:
- 使用
xxx.xxx方法
String respJson = HttpInvoker.httpGet(leader.getUrl() + "/test");
JSON.parseObject(respJson, Test.class)
- 输入
...数据
public class Test{
LinkedMultiValueMap<String, InstanceMeta> test_1;
Map<String, Long> test_2;
Map<String, Long> test_3;
long test_4;
}
- 出现
...错误
java.lang.ClassCastException create breakpoint : clas com.alibaba.fastjson2.JS0N0bject cannot be cast to class'cn.XX (com.alibaba.fastjson2.u0Nobject and cn.XX are in unnamed module of loader 'app')at cn.XX)~[classes/:na]
https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.50-SNAPSHOT/ 问题已修复,请帮忙用2.0.50-SNAPSHOT版本验证
@wenshao 2.0.50版本计划什么时候发布
2.0.50计划在5月12日前发布
我这种嵌套太多的还是不行
错误
class cn.xx.core.model.InstanceMeta cannot be cast to class java.util.List (cn.xx.core.model.InstanceMeta is in unnamed module of loader 'app'; java.util.List is in module java.base of loader 'bootstrap')
数据
{"registry":{"cn.xx.UserService":[{"schema":"http","host":"127.0.0.1","port":8082,"context":"trpc","status":true,"parameters":{"env":"dev","tag":"red"}}]},"timestamps":{"cn.xx.UserService@http://127.0.0.1:8082/trpc":1714442794280},"versions":{"cn.xx.UserService":1},"version":1}
@Data
@AllArgsConstructor
public class Snapshot {
/**
* 注册上来的服务集
*/
// @JSONField(deserializeUsing = LinkedMultiValueMapDeserializer.class)
LinkedMultiValueMap<String, InstanceMeta> registry;
/**
* 实例时间戳 - 实例级别
* (service + "@" + instance.toUrl(),时间戳)
*/
Map<String, Long> timestamps;
/**
* 服务的版本 - 服务级别
*/
Map<String, Long> versions;
/**
* VERSIONS#value
*/
long version;
}
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = {"schema", "host", "port", "context"})
public class InstanceMeta {
/**
* 协议 [http]
*/
private String schema;
/**
* host
*/
private String host;
/**
* port
*/
private Integer port;
/**
* 上下文
*/
private String context;
/**
* 服务状态
*/
private Boolean status;
}
方法
// 都尝试过
JSON.to(clazz, respJson)
JSON.parseObject(respJson, typeReference);
我目前的解决方案给别人参考一下:可行的
public class LinkedMultiValueMapDeserializer implements ObjectReader<LinkedMultiValueMap<String, InstanceMeta>> {
@Override
public LinkedMultiValueMap<String, InstanceMeta> readObject(JSONReader jsonReader
, Type fieldType
, Object fieldName
, long features) {
LinkedMultiValueMap<String, InstanceMeta> linkedMultiValueMap = new LinkedMultiValueMap<>();
Map<String, Object> jsonObject = jsonReader.readObject();
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if(value instanceof JSONObject){
InstanceMeta instanceMeta = ((JSONObject) value).to(InstanceMeta.class);
linkedMultiValueMap.add(key, instanceMeta);
}else if(value instanceof JSONArray){
List<InstanceMeta> instanceMetas = JSONArray.parseArray(value.toString(), InstanceMeta.class);
linkedMultiValueMap.addAll(key, instanceMetas);
}
}
return linkedMultiValueMap;
}
}
@Data
@AllArgsConstructor
public class Snapshot {
@JSONField(deserializeUsing = LinkedMultiValueMapDeserializer.class)
LinkedMultiValueMap<String, InstanceMeta> registry;
}
package com.alibaba.fastjson2.issues_2400;
import com.alibaba.fastjson2.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.util.LinkedMultiValueMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
public class Issue2489 {
@Test
public void test() {
String str = "{\"registry\":{\"cn.xx.UserService\":[{\"schema\":\"http\",\"host\":\"127.0.0.1\",\"port\":8082,\"context\":\"trpc\",\"status\":true,\"parameters\":{\"env\":\"dev\",\"tag\":\"red\"}}]},\"timestamps\":{\"cn.xx.UserService@http://127.0.0.1:8082/trpc\":1714442794280},\"versions\":{\"cn.xx.UserService\":1},\"version\":1}\n";
Snapshot snapshot = JSON.parseObject(str, Snapshot.class);
assertEquals(1, snapshot.registry.size());
snapshot.registry.forEach((k, v) -> {
assertEquals(String.class, k.getClass());
for (InstanceMeta instanceMeta : v) {
assertNotNull(instanceMeta);
}
});
List<InstanceMeta> instanceMetas = snapshot.registry.get("cn.xx.UserService");
assertEquals(1, instanceMetas.size());
InstanceMeta instanceMeta = instanceMetas.get(0);
assertEquals("http", instanceMeta.schema);
}
@Data
@AllArgsConstructor
public static class Snapshot {
/**
* 注册上来的服务集
*/
// @JSONField(deserializeUsing = LinkedMultiValueMapDeserializer.class)
LinkedMultiValueMap<String, InstanceMeta> registry;
/**
* 实例时间戳 - 实例级别
* (service + "@" + instance.toUrl(),时间戳)
*/
Map<String, Long> timestamps;
/**
* 服务的版本 - 服务级别
*/
Map<String, Long> versions;
/**
* VERSIONS#value
*/
long version;
}
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = {"schema", "host", "port", "context"})
public static class InstanceMeta {
private String schema;
private String host;
private Integer port;
private String context;
private Boolean status;
}
}
我测试没问题啊
https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.50-SNAPSHOT/ 问题已修复,请帮忙再更新2.0.50-SNAPSHOT版本验证
https://github.com/alibaba/fastjson2/releases/tag/2.0.50 2.0.50已发布,请用新版本