I have the following 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
}
]
}
}
Under the lineDiagnostics, we have the "C4000LG2020253739": {...} and I need the contents from inside this object for my further calculations, could anyone please let me know how can this be achieved?
I am using Jackson to map the JSON values to a Java class.
Note: This particular string value "C4000LG2020253739":{...} will change with every microservice call(and not the contents inside this{...}), so I am facing problem with creating a general purpose Java class for this JSON structure.
I am using Jackson to map the JSON values to a Java class:
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;
...}
Inside the LineDiagnostics object, I need to map the "C4000LG2020253739":{...} from JSON, how can this be done? any pointers?
At least you can deserialize json to Map
and retrieve required data from it.
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());
}
But I recommend you to build a model and use it instead of Map
.
Simple model could look like this:
@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;
}
}
And your business code like:
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());
}
And finally. You can solve your problem with mup Map<String, Object>
inside LineDiagnostics
and define setter with @JsonAnySetter
annotation.
@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;
}
}
And your final result should look like this:
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);
}