alibaba / fastjson2

🚄 FASTJSON2 is a Java JSON library with excellent performance.
Apache License 2.0
3.74k stars 484 forks source link

[BUG]对象包含有序集合,反序列化时乱序 #2736

Open allenwoody opened 4 months ago

allenwoody commented 4 months ago

问题描述

包含TreeSet属性的对象,在序列化反序列化时TreeSet内值乱序

环境信息

重现步骤

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

  1. 执行 main 方法
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;

import static com.alibaba.fastjson2.JSONReader.Feature.UseDefaultConstructorAsPossible;

@Data
public class TrainingDataParamsSet {

    @ApiModelProperty(value = "算法")
    private Set<String> algorithms;

    /**
     * 平滑系数,lambda
     */
    @ApiModelProperty(value = "平滑系数,lambda")
    private Set<BigDecimal> algorithmParameters;

    /**
     * 阈值
     */
    @ApiModelProperty(value = "阈值")
    private Set<BigDecimal> thresholds;

    /**
     * 截断方式,1.去除-remove, 2-替换-replace
     */
    @ApiModelProperty(value = "截断方式,1.去除-remove, 2-替换-replace")
    private Set<Integer> truncationMethods;

    /**
     * 截断率
     */
    @ApiModelProperty(value = "截断率")
    private Set<BigDecimal> truncationRates;

    /**
     * 步长
     */
    @ApiModelProperty(value = "步长")
    private Set<Integer> steps;

    /**
     * 误差引入方式
     */
    @ApiModelProperty(value = "误差引入方式")
    private Set<String> errorIntroductionMethods;

    /**
     * 系统误差-恒定误差
     */
    @ApiModelProperty(value = "系统误差-恒定误差")
    private Set<BigDecimal> systematicErrors;

    /**
     * 系统误差-比例误差
     */
    @ApiModelProperty(value = "系统误差-比例误差")
    private Set<BigDecimal> proportionalErrors;

    /**
     * 高斯分布标准差
     */
    @ApiModelProperty(value = "高斯分布标准差")
    private Set<BigDecimal> gaussianStds;

    /**
     * 高斯分布均值
     */
    @ApiModelProperty(value = "高斯分布均值")
    private Set<BigDecimal> gaussianMeans;

    /**
     * U型分布标准差
     */
    @JSONField(name = "uShapedStds")
    @ApiModelProperty(value = "U型分布标准差")
    private Set<BigDecimal> uShapedStds;

    /**
     * U型分布均值
     */
    @JSONField(name = "uShapedMeans")
    @ApiModelProperty(value = "U型分布均值")
    private Set<BigDecimal> uShapedMeans;

    /**
     * 均匀分布标准差
     */
    @ApiModelProperty(value = "均匀分布标准差")
    private Set<BigDecimal> uniformStds;

    /**
     * FPR1,falsePositiveRate,假阳率
     */
    @ApiModelProperty(value = "FPR1,falsePositiveRate,假阳率")
    private ValueRange fpr1s;

    /**
     * TPR1,truePositiveRate,真阳率
     */
    @ApiModelProperty(value = "TPR1,truePositiveRate,真阳率")
    private ValueRange tpr1s;

    /**
     * ANped(Adult Neutrophil per Erythroid cell division)骨髓中成人中性粒细胞与红细胞生成细胞之间的比率
     */
    @JSONField(name = "aNped")
    @ApiModelProperty(value = "ANped(Adult Neutrophil per Erythroid cell division)骨髓中成人中性粒细胞与红细胞生成细胞之间的比率")
    private ValueRange aNpeds;

    /**
     * MNped(Mature Neutrophil per Erythroid cell division)骨髓中成熟中性粒细胞与红细胞生成细胞之间的比率
     */
    @JSONField(name = "mNped")
    @ApiModelProperty(value = "MNped(Mature Neutrophil per Erythroid cell division)骨髓中成熟中性粒细胞与红细胞生成细胞之间的比率")
    private ValueRange mNpeds;

    /**
     * Nped95,95% 阴性预测值(95% NPV, NPed95)
     */
    @ApiModelProperty(value = "Nped95,95% 阴性预测值(95% NPV, NPed95)")
    private ValueRange nped95s;

    /**
     * 不稳定指标
     */
    @ApiModelProperty(value = "不稳定指标")
    private ValueRange instabilityIndices;

    // 构造方法
    public TrainingDataParamsSet() {
        // 初始化所有 Set 类型属性为 TreeSet
        this.algorithms = new TreeSet<>();
        this.algorithmParameters = new TreeSet<>();
        this.thresholds = new TreeSet<>();
        this.truncationMethods = new TreeSet<>();
        this.truncationRates = new TreeSet<>();
        this.steps = new TreeSet<>();
        this.errorIntroductionMethods = new TreeSet<>();
        this.systematicErrors = new TreeSet<>();
        this.proportionalErrors = new TreeSet<>();
        this.gaussianStds = new TreeSet<>();
        this.gaussianMeans = new TreeSet<>();
        this.uShapedStds = new TreeSet<>();
        this.uShapedMeans = new TreeSet<>();
        this.uniformStds = new TreeSet<>();
        this.fpr1s = new ValueRange();
        this.tpr1s = new ValueRange();
        this.aNpeds = new ValueRange();
        this.mNpeds = new ValueRange();
        this.nped95s = new ValueRange();
        this.instabilityIndices = new ValueRange();
    }

    public static void main(String[] args) {
        // 实例化 TrainingDataParamsSet 对象并设置属性值
        TrainingDataParamsSet trainingDataParamsSet = new TrainingDataParamsSet();

        // 设置属性值
        trainingDataParamsSet.setSteps(new TreeSet<>(Arrays.asList(10, 30, 50, 70, 100, 130, 150, 200)));
        trainingDataParamsSet.setAlgorithms(new TreeSet<>(Arrays.asList("ewma", "ma")));
        trainingDataParamsSet.setUShapedStds(new TreeSet<>(Arrays.asList(new BigDecimal("0.33"), new BigDecimal("0.5"), new BigDecimal("1.5"), new BigDecimal("3.0"))));
        trainingDataParamsSet.setUShapedMeans(new TreeSet<>(Arrays.asList(new BigDecimal("-0.5"), new BigDecimal("-0.3"), BigDecimal.ZERO, new BigDecimal("0.3"), new BigDecimal("0.5"))));
        trainingDataParamsSet.setTruncationRates(new TreeSet<>(Arrays.asList(new BigDecimal("0.01"), new BigDecimal("0.02"), new BigDecimal("0.03"), new BigDecimal("0.04"), new BigDecimal("0.05"), new BigDecimal("0.1"), new BigDecimal("0.2"))));
        trainingDataParamsSet.setTruncationMethods(new TreeSet<>(Arrays.asList(1, 2)));
        trainingDataParamsSet.setErrorIntroductionMethods(new TreeSet<>(Arrays.asList("even", "gauss", "ratio", "stable", "u")));
        String json = JSON.toJSONString(trainingDataParamsSet);
        System.out.println(json);
        TrainingDataParamsSet t = JSON.parseObject(json, TrainingDataParamsSet.class);
        System.out.println("----");
        System.out.println(t);
    }

}

期待的正确结果

通过JSON.parseObject(json, TrainingDataParamsSet.class);得到的对象,里面的TreeSet实例是有序的

相关日志输出

{"aNped":{},"algorithmParameters":[],"algorithms":["ewma","ma"],"errorIntroductionMethods":["even","gauss","ratio","stable","u"],"fpr1s":{},"gaussianMeans":[],"gaussianStds":[],"instabilityIndices":{},"mNped":{},"nped95s":{},"proportionalErrors":[],"steps":[10,30,50,70,100,130,150,200],"systematicErrors":[],"thresholds":[],"tpr1s":{},"truncationMethods":[1,2],"truncationRates":[0.01,0.02,0.03,0.04,0.05,0.1,0.2],"uShapedMeans":[-0.5,-0.3,0,0.3,0.5],"uShapedStds":[0.33,0.5,1.5,3.0],"uniformStds":[]}

TrainingDataParamsSet(algorithms=[ma, ewma], algorithmParameters=[], thresholds=[], truncationMethods=[1, 2], truncationRates=[0.02, 0.1, 0.01, 0.05, 0.04, 0.03, 0.2], steps=[50, 130, 100, 70, 150, 200, 10, 30], errorIntroductionMethods=[gauss, even, u, stable, ratio], systematicErrors=[], proportionalErrors=[], gaussianStds=[], gaussianMeans=[], uShapedStds=[0.33, 1.5, 3.0, 0.5], uShapedMeans=[0, -0.5, -0.3, 0.5, 0.3], uniformStds=[], fpr1s=ValueRange(max=null, min=null), tpr1s=ValueRange(max=null, min=null), aNpeds=ValueRange(max=null, min=null), mNpeds=ValueRange(max=null, min=null), nped95s=ValueRange(max=null, min=null), instabilityIndices=ValueRange(max=null, min=null))

附加信息

allenwoody commented 4 months ago

看了下源码,应该是我用Set声明变量的锅,反序列化时直接变成HashSet了 改用TreeSet声明就没问题。还是想问问,用Set声明就不行吗