Search code examples
jsonpojo

Not able to Parse JSON data to POJO


I have JSON data with following structure. I have tried creating POJOs with same structure and with same names. I have taken a DTO which contains a list (of DTOs with structure of the numeral objects in the following JSON) and a String "Notice". I am not able to get the data in the DTO.

{
    "notice": "This API is in a pre-launch state, and will go through significant changes.",
    "1": {
        "next_renewal_date": "2014-08-01",
        "next_renewal_fee": {
            "price": "800.0",
            "currency": "USD"
        },
        "next_renewal_description": "1st Annuity - Official Fee",
        "next_per_claim_fee": {
            "price": "0.0",
            "currency": "USD",
            "free_claims": 0,
            "claim_type": "claims_count"
        },
        "next_agent_fee": {
            "price": "0.0",
            "currency": "USD"
        },
        "grace_period_end_date": "2015-02-01"
    },
    "2": {
        "next_renewal_date": "2018-08-01",
        "next_renewal_fee": {
            "price": "1800.0",
            "currency": "USD"
        },
        "next_renewal_description": "2nd Annuity - Official Fee",
        "next_per_claim_fee": {
            "price": "0.0",
            "currency": "USD",
            "free_claims": 0,
            "claim_type": "claims_count"
        },
        "next_agent_fee": {
            "price": "0.0",
            "currency": "USD"
        },
        "grace_period_end_date": "2019-02-01"
    }
}

POJO:

public class RenewalAPICallListDTO {
    private Map<Integer,JSONCallDto> apiCallList;

    public Map<Integer, JSONCallDto> getApiCallList() {
        return apiCallList;
    }
    public void setApiCallList(Map<Integer, JSONCallDto> apiCallList) {
        this.apiCallList = apiCallList;
    }
    private String notice;

    public String getNotice() {
        return notice;
    }
    public void setNotice(String notice) {
        this.notice = notice;
    }
}

Method call:

Gson gson = new Gson();
RenewalAPICallListDTO respDto = gson.fromJson(response1.toString(), RenewalAPICallListDTO.class);

Solution

  • What you are looking for can be achieve with Jackson with a custom deserializer, as the following:

    public class CustomDeserializer extends JsonDeserializer<RenewalAPICallListDTO> {
    
        private static final ObjectMapper mapper = new ObjectMapper();
    
        static {
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
    
        @Override
        public RenewalAPICallListDTO deserialize(JsonParser jp, DeserializationContext ctxt)
                throws IOException {
    
    
            JsonNode node = jp.getCodec().readTree(jp);
    
            Iterator<Entry<String, JsonNode>> nodeIterator = node.fields();
    
            RenewalAPICallListDTO dto = new RenewalAPICallListDTO();
            Map<Integer, JsonCallDto> map = new HashMap<>();
    
            while (nodeIterator.hasNext()) {
                Map.Entry<String, JsonNode> entry = nodeIterator.next();
                if (entry.getKey().equalsIgnoreCase("notice")) {
                    dto.setNotice(entry.getValue().toString());
                } else {
                    map.put(Integer.parseInt(entry.getKey()), mapper.readValue(entry.getValue().toString(), JsonCallDto.class));
                }
            }
            dto.setApiCallList(map);
            return dto;
        }
    
    }
    

    Usage:

    public static void main(String[] args) throws Exception {
    
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(RenewalAPICallListDTO.class, new CustomDeserializer());
        mapper.registerModule(module);
    
        RenewalAPICallListDTO dto = mapper.readValue(JSON, RenewalAPICallListDTO.class);
    } 
    

    The final dto will be correctly serialized like you want, even with the correct types already set.