skip to Main Content
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MatchingResponse {
    @JsonProperty(value = "Code")
    private String code;
    @JsonProperty(value = "Msg")
    private String message;
    @JsonProperty(value = "Id")
    private int id;
    @JsonProperty(value = "Date")
    private String date;
    @JsonProperty(value = "ClientIin")
    private String clientIin;
    @JsonProperty(value = "Similarity")
    private String similarity;
    @JsonProperty(value = "VendorName")
    private String vendorName;
}

This is my class. I`m trying to deserialize this JSON:

{
    "Code": "200",
    "Msg": "",
    "Id": 20148,
    "Date": "2023-08-01T15:21:13.9704572+06:00",
    "ClientIin": "888888888888",
    "Similarity": "0.007720462",
    "VendorName": "SomeName"
}

to my custom class with this code:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
byte[] byteResponse = httpResponse.getEntity().getContent().readAllBytes();
MatchingResponse response = mapper.readValue(byteResponse, MatchingResponse.class);

but because of JSON has empty variable "Msg", I`m getting exception:

Cannot construct instance of `MatchingResponse` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"Code":"200","Msg":"","Id":20148,"Date":"2023-08-01T15:18:03.883337+06:00","ClientIin":"888888888888","Similarity":"0.0738383234","VendorName":"SomeName"}')
 at [Source: (byte[])""{"Code":"200","Msg":"","Id":20147,"Date":"2023-08-01T15:18:03.883337+06:00","ClientIin":"830921301593","Similarity":"0.0738383234","VendorName":"VisionLabs"}""; line: 1, column: 1]

I tried creating JsonSetter:

@JsonSetter
    public void setMessage(String message) {
        if (message != null && message.isEmpty()) {
            this.message = null;
        } else {
            this.message = message;
        }
    }

like this or tried creating deserializers:

public class MatchingResponseDeserializer extends StdDeserializer<MatchingResponse> {
    public MatchingResponseDeserializer() {
        this(null);
    }

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

    @Override
    public MatchingResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        String code = getOptionalString(node, "Code");
        String message = getOptionalString(node, "Msg");
        int id = getOptionalInt(node, "Id");
        String date = getOptionalString(node, "Date");
        String clientIin = getOptionalString(node, "ClientIin");
        String similarity = getOptionalString(node, "Similarity");
        String vendorName = getOptionalString(node, "VendorName");

        return new MatchingResponse(code, message, id, date, clientIin, similarity, vendorName);
    }

    private String getOptionalString(JsonNode node, String fieldName) {
        JsonNode valueNode = node.get(fieldName);
        return (valueNode != null) ? valueNode.asText() : null;
    }

    private int getOptionalInt(JsonNode node, String fieldName) {
        JsonNode valueNode = node.get(fieldName);
        return (valueNode != null) ? valueNode.asInt() : 0; // Provide a default value if needed
    }
}

Set this deserializer to the class:

@JsonDeserialize(using = MatchingResponseDeserializer.class)
public class MatchingResponse {

This deserializer:

public class EmptyStringDeserializer extends JsonDeserializer<String> {

    public EmptyStringDeserializer() {
        this(null);
    }

    public EmptyStringDeserializer(Class<?> vc) {
        super(vc);
    }
    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        JsonNode node = jsonParser.readValueAsTree();
        if (node.asText().isEmpty()) {
            return null;
        }
        return node.toString();
    }
}

I set to variable:

@JsonProperty(value = "Msg")
@JsonDeserialize(using = EmptyStringDeserializer.class)
private String message;

but none of it worked.

I tried use Gson, but get exception:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $

So my question is, how can I fix this error? How to work with empty JSON variables?

3

Answers


  1. You can try:

    ObjectMapper mapper = new ObjectMapper();
    byte[] byteResponse = httpResponse.getEntity().getContent().readAllBytes();
    String jsonString = new String(byteResponse); // parse byte array to String
    JsonNode rootNode = mapper.readTree(jsonString); // parse String to JsonNode
    MatchingResponse response = mapper.treeToValue(rootNode, MatchingResponse.class); // parse JsonNode to your object
    

    The mapper.readTree(jsonString) parses the string into a JsonNode, which is Jackson’s tree model for JSON.mapper.treeToValue(rootNode, MatchingResponse.class) then converts this tree into your object.

    Also, you don’t need to enable DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT. Jackson automatically converts empty strings in the JSON to empty strings in the object, not null.

    Login or Signup to reply.
  2. Why don’t you try using json as jsonString and use

    MatchingResponse matchingResponse = objectMapper.readValue(jsonString, MatchingResponse.class);
    

    instead of byte[]

    Login or Signup to reply.
  3. try removing @AllArgsConstructor, a small test without Lombok works fine…

    I guess there’s some issue with missing @JsonCreator annotation on the constructor generated by Lombok.

    package com.example.demo;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    public class MatchingResponse {
        @JsonProperty(value = "Code")
        private String code;
        @JsonProperty(value = "Msg")
        private String message;
        @JsonProperty(value = "Id")
        private int id;
        @JsonProperty(value = "Date")
        private String date;
        @JsonProperty(value = "ClientIin")
        private String clientIin;
        @JsonProperty(value = "Similarity")
        private String similarity;
        @JsonProperty(value = "VendorName")
        private String vendorName;
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setDate(String date) {
            this.date = date;
        }
    
        public void setClientIin(String clientIin) {
            this.clientIin = clientIin;
        }
    
        public void setSimilarity(String similarity) {
            this.similarity = similarity;
        }
    
        public void setVendorName(String vendorName) {
            this.vendorName = vendorName;
        }
    
        public String getCode() {
            return code;
        }
    
        public String getMessage() {
            return message;
        }
    
        public int getId() {
            return id;
        }
    
        public String getDate() {
            return date;
        }
    
        public String getClientIin() {
            return clientIin;
        }
    
        public String getSimilarity() {
            return similarity;
        }
    
        public String getVendorName() {
            return vendorName;
        }
    }
    
    
    
    @Test
    void deserialize() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        MatchingResponse matchingResponse = mapper.readValue(getClass().getResourceAsStream("/msg.json"), MatchingResponse.class);
    
        assertNotNull(matchingResponse);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search