I have a JSON String:
{
"productName": "Gold",
"offerStartDate": "01152023",
"offerEndDate": "01152024",
"offerAttributes": [
{
"id": "TGH-DAD3KVF3",
"storeid": "STG-67925",
"availability": true
}
],
"offerSpecifications": {
"price": 23.25
}
}
The validation logic for the same is written as
Map<String, Object> map = mapper.readValue(json, Map.class);
String productNameValue = (String)map.get("productName");
if(productNameValue ==null && productNameValue.isEmpty()) {
throw new Exception();
}
String offerStartDateValue = (String)map.get("offerStartDate");
if(offerStartDateValue ==null && offerStartDateValue.isEmpty()) {
throw new Exception();
}
List<Object> offerAttributesValue = (List)map.get("offerAttributes");
if(offerAttributesValue ==null && offerAttributesValue.isEmpty()) {
throw new Exception();
}
Map<String, Object> offerSpecificationsValue = (Map)map.get("offerSpecifications");
if(offerSpecificationsValue ==null && offerSpecificationsValue.isEmpty() && ((String)offerSpecificationsValue.get("price")).isEmpty()) {
throw new Exception();
}
This is a portion of the JSON response. The actual response has more than 48 fields and the. The existing code has validation implemented for all the 48 fields as above. Note the responses are way complex than these.
I feel the validation code has very verbose and is very repetitive. How do, I fix this? What design pattern should I use to write a validation logic. I have seen builder pattern, but not sure how to use it for this scenario.
Build a JSON template for comparison.
ObjectMapper mapper = new ObjectMapper();
JsonNode template = mapper.readTree(
"{" +
" \"productName\": \"\"," +
" \"offerStartDate\": \"\"," +
" \"offerEndDate\": \"\"," +
" \"offerAttributes\": []," +
" \"offerSpecifications\": {" +
" \"price\": 0" +
" }" +
"}");
JsonNode data = mapper.readTree(
"{" +
" \"productName\": \"Gold\"," +
" \"offerStartDate\": \"01152023\"," +
" \"offerEndDate\": \"01152024\"," +
" \"offerAttributes\": [" +
" {" +
" \"id\": \"TGH-DAD3KVF3\"," +
" \"storeid\": \"STG-67925\"," +
" \"availability\": true" +
" }" +
" ]," +
" \"offerSpecifications\": {" +
" \"price\": 23.25" +
" }" +
"}");
validate(template, data);
Here is the recursion function to compare the template and the data.
public void validate(JsonNode template, JsonNode data) throws Exception {
final Iterator<Map.Entry<String, JsonNode>> iterator = template.fields();
while (iterator.hasNext()) {
final Map.Entry<String, JsonNode> entry = iterator.next();
JsonNode dataValue = data.get(entry.getKey());
if (dataValue == null || dataValue.isNull()) {
throw new Exception("Missing " + entry.getKey());
}
if (entry.getValue().getNodeType() != dataValue.getNodeType()) {
throw new Exception("Mismatch data type: " + entry.getKey());
}
switch (entry.getValue().getNodeType()) {
case STRING:
if (dataValue.asText().isEmpty()) {
throw new Exception("Missing " + entry.getKey());
}
break;
case OBJECT:
validate(entry.getValue(), dataValue);
break;
case ARRAY:
if (dataValue.isEmpty()) {
throw new Exception("Array " + entry.getKey() + " must not be empty");
}
break;
}
}
}