fastjson2 icon indicating copy to clipboard operation
fastjson2 copied to clipboard

[BUG] 反序列化 LinkedMultiValueMap时Array 变成了 JSONArray

Open en-o opened this issue 1 year ago • 7 comments

问题描述

我在接口请求数据 JSON.parseObject(respJson, LinkedMultiValueMap) 发现数据类型不一致,导致我后续的removeif出错

环境信息

请填写以下信息:

  • OS信息: windows
  • JDK信息:azul-17.0.10
  • 版本信息:Fastjson2.0.47

重现步骤

如何操作可以重现该问题:

  1. 使用 xxx.xxx 方法
String respJson = HttpInvoker.httpGet(leader.getUrl() + "/test");
JSON.parseObject(respJson, Test.class)
  1. 输入 ... 数据
public class Test{
    LinkedMultiValueMap<String, InstanceMeta> test_1;
    Map<String, Long> test_2;
    Map<String, Long> test_3;
    long test_4;
}
  1. 出现 ... 错误
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]

image

en-o avatar Apr 26 '24 07:04 en-o

https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.50-SNAPSHOT/ 问题已修复,请帮忙用2.0.50-SNAPSHOT版本验证

wenshao avatar Apr 27 '24 15:04 wenshao

@wenshao 2.0.50版本计划什么时候发布

805728578 avatar Apr 29 '24 00:04 805728578

2.0.50计划在5月12日前发布

wenshao avatar Apr 29 '24 01:04 wenshao

我这种嵌套太多的还是不行

错误

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);

en-o avatar Apr 30 '24 02:04 en-o

我目前的解决方案给别人参考一下:可行的

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;
}

en-o avatar Apr 30 '24 02:04 en-o

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;
    }
}

我测试没问题啊

wenshao avatar May 03 '24 00:05 wenshao

https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.50-SNAPSHOT/ 问题已修复,请帮忙再更新2.0.50-SNAPSHOT版本验证

wenshao avatar May 03 '24 02:05 wenshao

https://github.com/alibaba/fastjson2/releases/tag/2.0.50 2.0.50已发布,请用新版本

wenshao avatar May 12 '24 05:05 wenshao