如何将字符串常量对象从 JSON 解编为 Java 对象?

How to unmarshall a string constant object from JSON to as a Java Object?

提问人:Shanky 提问时间:11/2/2023 最后编辑:Oleg CherednikShanky 更新时间:11/2/2023 访问量:65

问:

我有以下JSON:

{
  "code":1000,
  "message":"Success",
  "data":{
    "results":[
      {
        "lineId":"C4000LG2020253739",
        "lineDiagnostics":{
          "C4000LG2020253739":{
            "ap":{
              "broadbanddsthroughput":{
                "broadbandDsThroughput":[
                  {
                    "average":104830,
                    "std":0,
                    "detection":0,
                    "numErrorFreeSamples":1,
                    "sampleMaxPercentile":107673,
                    "latestSampleTimestamp":1698160893000,
                    "sampleMax":107673,
                    "url":"http://blah-blah.com",
                    "videoQuality":7,
                    "serviceDetection":-1,
                    "percentile":[
                      104830
                    ],
                    "latestSample":104830,
                    "primaryIp":"205.171.3.100",
                    "speedTestTrafficMB":56.9910995
                  }
                ]
              },
              "broadbandusthroughput":{
                "broadbandUsThroughput":[
                  {
                    "average":37828,
                    "std":0,
                    "numErrorFreeSamples":1,
                    "sampleMaxPercentile":38393,
                    "latestSampleTimestamp":1698160893000,
                    "sampleMax":38393,
                    "url":"http://blah-blah.com",
                    "serviceDetection":-1,
                    "percentile":[
                      37828
                    ],
                    "latestSample":37828,
                    "primaryIp":"205.171.3.100",
                    "speedTestTrafficMB":21.8231345
                  }
                ]
              }
            },
            "interface":{
              
            },
            "station":{
              
            },
            "multiWan":{
              
            }
          }
        },
        "analysisDay":20231024
      }
    ]
  }
}

在行 Diagnostics 下,我们有“C4000LG2020253739”: {...},我需要这个对象内部的内容进行进一步计算,任何人都可以告诉我如何实现这一点吗?

我正在使用 Jackson 将 JSON 值映射到 Java 类。

注意:这个特定的字符串值“C4000LG2020253739”:{...} 会随着每次微服务调用而改变(而不是 this{...} 中的内容),所以我在为此 JSON 结构创建通用 Java 类时遇到了问题。

我正在使用 Jackson 将 JSON 值映射到 Java 类:

public class Class1{
    //historical speed response structure : map from json response
    String code;
    String message;

    @JsonProperty("data")
    DataSpeeds dataSpeeds;
...}

public class DataSpeeds {
    @JsonProperty("results")
    List<Results> results;

    @JsonProperty("lineId")
    String lineId;
...}

public class Results {

    String lineId;

    @JsonProperty("lineDiagnostics")
    LineDiagnostics lineDiagnostics;
...}

public class LineDiagnostics {
    @JsonProperty("ap")
    Ap ap;
...}

在 LineDiagnostics 对象中,我需要从 JSON 映射“C4000LG2020253739”:{...},这怎么能做到?有什么建议吗?

java json 微服务 jackson-databind objectmapper

评论

3赞 Robby Cornelissen 11/2/2023
只需将对象映射到 .LineDiagnosticsHashMap
1赞 Sree Kumar 11/2/2023
虽然@RobbyCornelissen已经提到过,但我想对此进行扩展。在类中,将字段的类型更改为 plain .然后,Jackson 将用 等填充此映射的键,并将值填充为相应的未编组实例。ResultlineDiagnosticsMap<String, LineDiagnostics>LineDiagnosticsC4000LG2020253739LineDiagnostics

答:

1赞 Oleg Cherednik 11/2/2023 #1

选项 1

至少你可以将 json 反序列化并从中检索所需的数据。Map

public static Map<String, Object> getLineDiagnosticByLineId(File file, String lineId) throws IOException {
    TypeReference<HashMap<String, Object>> typeRef = new TypeReference<>() {
    };

    Map<String, Object> map = new ObjectMapper().readValue(file, typeRef);
    Map<String, Object> data = (Map<String, Object>) map.getOrDefault("data", Map.of());
    List<Object> results = (List<Object>) data.getOrDefault("results", List.of());

    return results.stream()
            .map(result -> (Map<String, Object>) result)
            .filter(result -> lineId.equals(result.get("lineId")))
            .map(result -> result.getOrDefault("lineDiagnostics", List.of()))
            .map(lineDiagnostics -> (Map<String, Object>) lineDiagnostics)
            .findFirst().orElse(Map.of());
}

选项 2

但我建议你建立一个模型,用它来代替.Map

简单模型可能如下所示:

@Getter
@Setter
public class DataModel {

    private Integer code;
    private String message;
    private Data data;

    @Getter
    @Setter
    public static class Data {

        private List<Result> results;

    }

    @Getter
    @Setter
    public static class Result {

        private String lineId;
        private Map<String, Object> lineDiagnostics;
        private Integer analysisDay;

    }

}

您的业务代码如下:

public static Map<String, Object> getLineDiagnosticByLineId(File file, String lineId) throws IOException {
    DataModel dataModel = new ObjectMapper().readValue(file, DataModel.class);
    return dataModel.getData().getResults().stream()
            .filter(result -> lineId.equals(result.getLineId()))
            .map(DataModel.Result::getLineDiagnostics)
            .findFirst().orElse(Map.of());
}

选项 3

最后。你可以用里面的 mup 来解决你的问题,并用注解定义 setter。Map<String, Object>LineDiagnostics@JsonAnySetter

@Getter
@Setter
public class DataModel {

    private Integer code;
    private String message;
    private Data data;

    @Getter
    @Setter
    public static class Data {

        private List<Result> results;

    }

    @Getter
    @Setter
    public static class Result {

        private String lineId;
        private LineDiagnostics lineDiagnostics;
        private Integer analysisDay;

    }

    @Getter
    @Setter
    public static class LineDiagnostics {

        private Map<String, LineDiagnostic> lineDiagnostics = new HashMap<>();

        @JsonAnySetter
        public void setLineDiagnostic(String key, LineDiagnostic value) {
            lineDiagnostics.put(key, value);
        }

    }

    @Getter
    @Setter
    public static class LineDiagnostic {

        private Ap ap;
        @JsonProperty("interface")
        private Object anInterface;
        private Object station;
        private Object multiWan;

    }

    @Getter
    @Setter
    public static class Ap {

        @JsonProperty("broadbanddsthroughput")
        private BroadbandDsThroughput broadbandDsThroughput;
        @JsonProperty("broadbandusthroughput")
        private BroadbandUsThroughput broadbandUsThroughput;

    }

    @Getter
    @Setter
    public static class BroadbandDsThroughput {

        private List<BroadbandThroughput> broadbandDsThroughput;

    }

    @Getter
    @Setter
    public static class BroadbandUsThroughput {

        private List<BroadbandThroughput> broadbandUsThroughput;

    }

    @Getter
    @Setter
    public static class BroadbandThroughput {

        private Double average;
        private Double std;
        private Double detection;
        private Integer numErrorFreeSamples;
        private Integer sampleMaxPercentile;
        private Long latestSampleTimestamp;
        private Integer sampleMax;
        private String url;
        private Integer videoQuality;
        private Integer serviceDetection;
        private List<Integer> percentile;
        private Integer latestSample;
        private String primaryIp;
        @JsonProperty("speedTestTrafficMB")
        private Double speedTestTrafficMb;

    }

}

最终结果应如下所示:

public static DataModel.LineDiagnostics getLineDiagnosticByLineId(File file, String lineId) throws IOException {
    DataModel dataModel = new ObjectMapper().readValue(file, DataModel.class);
    
    return dataModel.getData().getResults().stream()
            .filter(result -> lineId.equals(result.getLineId()))
            .map(DataModel.Result::getLineDiagnostics)
            .findFirst().orElse(null);
}

评论

0赞 Shanky 11/3/2023
这是一个很好的答案!我一直在寻找这样的POJO。也许你错过了一个“s”:@JsonAnySetter setLineDiagnostics(...)这解决了我的问题。非常感谢!