aazeem
aazeem

Reputation: 864

Jackson custom deserializer String to List, and remove \r\n

I am getting the following JSON as response from a service. I am using Spring RestTemplate to call the service which also deserializes the JSON back into an Object. I am trying to deserialize it into an Object that has a List besides other fields. I am getting the following error while deserializing:

Can not instantiate value of type [simple type, class com.org.EmployeeInfo] from String value; no single-String constructor/factory method.

Following is the JSON that i want to deserialize:

{
    "employees": {       
        "employeeInfo": [
            "{\r\n  \"id\": \"123\",\r\n  \"group\": \"MARKETING\",\r\n  \"role\": \"MANAGER\",\r\n}",
            "{\r\n  \"id\": \"256\",\r\n  \"group\": \"IT\",\r\n  \"role\": \"DIRECTOR\",\r\n}",
            "{\r\n  \"id\": \"789\",\r\n  \"group\": \"SALES\",\r\n  \"role\": \"CEO\",\r\n}"
        ]
    },
    "status": "EMPLOYED",
    "somethingElse": {
        "something": []
    }
}

The default deserializer fails if i have the List<EmployeeInfo> in the object that i try to map the respone to, but it works if i use List<String> or String[]. This is because of the double quotes in the JSON (I am talking about "{\r\n) which makes it treat as a String

I am planning to write a custom deserializer to deserialize it into an object having List and also remove the \r\n that's part of the response. How can i do that? Appreciate any responses.

Here are my POJOs:

public class Response {
    private Employees employees;
    private String status;
    private SomethingElse somethingElse; 

   // getters, setters
}

public class Employees {
    List<EmployeeInfo> employeeInfo;
    // getters, setters
}

public class EmployeeInfo
{
   private String id, group, role;
   // getters, setters 
}

Thanks

Upvotes: 0

Views: 5722

Answers (2)

aazeem
aazeem

Reputation: 864

I worked around this problem in the following way (some of the logic needs to be optimized)

public class EmployeeInfoJsonDeserializer extends JsonDeserializer<List<EmployeeInfo>> {

    @Override
    public List<EmployeeInfo> deserialize(final JsonParser jp, final DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {

        final ObjectMapper mapper = (ObjectMapper) jp.getCodec();

        final JsonNode node = (JsonNode) mapper.readTree(jp);

        // TODO - Write the following logic in a better way
        String toStr = node.toString();
        toStr = StringUtils.replace(toStr, "\"{", "{");
        toStr = StringUtils.replace(toStr, "}\"", "}");
        toStr = StringUtils.remove(toStr, "\\r\\n");
        toStr = StringUtils.remove(toStr, "\\");

        final JsonNode newNode = mapper.readTree(toStr);

        final EmployeeInfo[] empInfo = mapper.convertValue(newNode, EmployeeInfo[].class);

        return Arrays.asList(empInfo);
    }
}

In the Pojo:

public class Employees {
       List<EmployeeInfo> employeeInfo;

       public List<EmployeeInfo> getEmployeeInfo() {
            return employeeInfo;
       }

       @JsonDeserialize(using = EmployeeInfoJsonDeserializer .class)
       public void setEmployeeInfo(final List<EmployeeInfo> employeeInfo) {
            this.employeeInfo= employeeInfo;
       }
}

Upvotes: 4

vzamanillo
vzamanillo

Reputation: 10404

That JSON is unparseable because is not valid, you can not deserialize it even if you have a custom deserializer.

Anyway, a custom deserializer example (does not work, is for learning purpouses only)

public class EmployeeInfoDeSerializer extends JsonDeserializer<List<EmployeeInfo>> {

    @Override
    public List<EmployeeInfo> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        // for learning purpouses only, does not work
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        List<EmployeeInfo> employeeInfos = new ArrayList<>();

        while (jp.nextToken() != JsonToken.END_OBJECT) {

            if (jp.getCurrentToken() != JsonToken.END_ARRAY) {

                JsonParser jParser = mapper.getJsonFactory().createJsonParser(jp.getText());
                employeeInfos.add(jParser.readValueAs(EmployeeInfo.class));
            }
        }
        return employeeInfos;
    }
}

in your Employees class

public class Employees {

    @JsonDeserialize(using=EmployeeInfoDeSerializer.class)
    private List<EmployeeInfo> employeeInfo;

    public List<EmployeeInfo> getEmployeeInfo() {
        return employeeInfo;
    }

    public void setEmployeeInfo(List<EmployeeInfo> employeeInfo) {
        this.employeeInfo = employeeInfo;
    }


}

Upvotes: 0

Related Questions