Skip to content

[BUG] fastjson2 2.0.56 使用 JSON.toJSONString 出现字段丢失 #3621

@midaug

Description

@midaug

问题描述

fastjson2 2.0.56 使用 JSON.toJSONString 出现字段丢失,打印的字符串里出现了字段丢失值为空的情况
测试发现,如果单独运行不会有问题,一旦另外一行JSON.toJSONString先运行了就会出现此情况
示例代码为了测试专门写的 demo,实际在接口的 service 层出现此问题,A单独调用时没有问题,一旦B接口先调用了A 接口就会百分百出现此问题导致业务报错

实测使用 jackson 没有此问题

环境信息

  • OS信息: [e.g.:arm MacOS 15.7 & amd Ubuntu 22]
  • JDK信息: [e.g.:Openjdk 17]
  • 版本信息:[e.g.:Fastjson2 2.0.56]

重现步骤

  1. 运行示例代码 main 方法
import com.alibaba.fastjson2.JSON;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class FastJson2Test {

    public static void main(String[] args) {
        SonInDto1 sonInDto1 = new SonInDto1("type.xxxxx1", "xxxxxx1", new SonInDto1.Data("张三"));
        SonInDto2 sonInDto2 = new SonInDto2("type.xxxxx2", "xxxxxx2", new SonInDto2.Data("风格"));
        System.out.println("sonInDto2: " + JSON.toJSONString(sonInDto2.buildWsRequest()));
        System.out.println("sonInDto1: " + JSON.toJSONString(sonInDto1.buildWsRequest()));
    }

    @Getter
    @Setter
    public static abstract class BaseInDto {
        protected String type;
        protected String traceId;

        @lombok.Data
        public static class Data {
            protected String query;
        }

        public abstract BaseInDto.Data getData();

        public OutDto buildWsRequest() {
            String[] tp = this.type.split("\\.");
            String method = tp[0];
            String subMethod = tp[1];
            OutDto inDto = new OutDto();
            inDto.setMethod(method);
            inDto.setSubMethod(subMethod);
            OutDto.Input input = new OutDto.Input();
            input.setType("text");
            input.setData(this.getData().getQuery());
            inDto.setInputs(new ArrayList<>(List.of(input)));
            return inDto;
        }
    }

    @Getter
    @Setter
    public static class SonInDto1 extends BaseInDto {
        protected SonInDto1.Data data;

        public SonInDto1(String type, String traceId, SonInDto1.Data data) {
            this.type = type;
            this.traceId = traceId;
            this.data = data;
        }

        @Getter
        @Setter
        public static class Data extends BaseInDto.Data {
            protected String name;

            public Data(String name) {
                this.name = name;
            }
        }

        @Getter
        @Setter
        public static class Extension extends OutDto.Extension {
            private SonInDto1.Data musicInfo;
        }

        @Override
        public OutDto buildWsRequest() {
            OutDto inDto = super.buildWsRequest();
            SonInDto1.Extension extension = new SonInDto1.Extension();
            this.data.setQuery(null);
            extension.setMusicInfo(this.data);
            inDto.setExtension(extension);
            inDto.setInputs(Collections.EMPTY_LIST);
            return inDto;
        }
    }

    @Getter
    @Setter
    public static class SonInDto2 extends BaseInDto {
        protected SonInDto2.Data data;

        public SonInDto2(String type, String traceId, SonInDto2.Data data) {
            this.type = type;
            this.traceId = traceId;
            this.data = data;
        }

        @Getter
        @Setter
        public static class Data extends BaseInDto.Data {
            protected String style;

            public Data(String style) {
                this.style = style;
            }
        }

        @Override
        public OutDto buildWsRequest() {
            OutDto inDto = super.buildWsRequest();
            OutDto.Extension extension = new OutDto.Extension();
            extension.setStyle(this.data.style);
            inDto.setExtension(extension);
            return inDto;
        }
    }


    @Getter
    @Setter
    public static class OutDto {
        private String method;
        private String subMethod;
        private List<OutDto.Input> inputs;
        private OutDto.Extension extension;

        @Getter
        @Setter
        public static class Input {
            protected String type;
            protected String data;
        }

        @Getter
        @Setter
        public static class Extension {
            protected String style;
            protected List<Object> history;
            protected String[] existingMusicIds;
        }
    }
}

期待的正确结果

正确结果:sonInDto1: {"extension":{"musicInfo":{"name":"张三"}},"inputs":[],"method":"type","subMethod":"xxxxx1"}

实际输出为错误的:sonInDto1: {"extension":{},"inputs":[],"method":"type","subMethod":"xxxxx1"}

Image

相关日志输出

sonInDto2: {"extension":{"style":"风格"},"inputs":[{"type":"text"}],"method":"type","subMethod":"xxxxx2"}
sonInDto1: {"extension":{},"inputs":[],"method":"type","subMethod":"xxxxx1"}

附加信息

当示例代码里的 System.out.println("sonInDto2和 System.out.println("sonInDto1 位置对调结果就是正确的
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixed

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions