简体   繁体   中英

Parsing JSON to Java having multiple data types for the same field

I have been given the below JSON:

{
  "dataBlock": [
    {
      "headingName": {
        "name": "Operational Information",
        "position": "1",
        "attributes": [
          {
            "name": "Brand",
            "position": "1",
            "value": [
              "A",
              "B"
            ]
          },
          {
            "name": "Data Model Id",
            "position": "2",
            "value": "000001"
          }
        ]
      }
    },
    {
      "headingName": {
        "name": "CRA",
        "position": "6",
        "attributes": [
          {
            "name": "Company",
            "position": "1",
            "value": "private_limited_company"
          },
          {
            "name": "Address",
            "position": "3",
            "value": {
              "line1": "AAA",
              "line2": "BBB",
              "line3": "CCC",
              "line4": "DDD",
              "postalCode": "AB XYZ",
              "countryCode": "GBR"
            }
          }
        ]
      }
    }
  ]
}

I need to convert it to Java. One thing you may notice is that "value" field of every "attribute" may be of type String. Object, Array or even a nested "attribute". How do I handle this case?

This is what I attempted:

MyService.java:

@Slf4j
@Service
public class MyService {
    public MyResponse getCustomerDetails() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            File file = getFile("classpath:data.json");
            if (file.exists()) {
                return mapper.readValue(file, MyResponse.class);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return null;
    }
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyResponse {
    private List<DataBlock> dataBlocks;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class DataBlock {
    @JsonProperty("headingName")
    private ComplianceSection section;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceSection {
    private String name;
    private String position;
    private List<ComplianceAttribute> attributes;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceAttribute {
    private String name;
    private String position;
//  private ComplianceAttributeValue value; ???
}

Not sure how can I map the value as it's structurally different for each attribute node.

try a custom deserializer

public class ComplianceAttributeValueDeserializer extends StdDeserializer<ComplianceAttributeValue> { 

    public ComplianceAttributeValueDeserializer() { 
        this(null); 
    } 

    public ComplianceAttributeValueDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public ComplianceAttributeValue deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);

        // detect value type and create object, e.g. for string type
        
        return new ComplianceAttributeStringValue(...);
    }
}

also use ComplianceAttributeValue as base class and derived classes for all known types like ComplianceAttributeStringValue or use generics

@JsonDeserialize(using = ComplianceAttributeValueDeserializer.class)
public class ComplianceAttributeValue {
...
}

https://www.baeldung.com/jackson-deserialization

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM