Spring + Jackson + Deserializing List of Generic O

2019-07-24 18:26发布

I have the following controller:

@RequestMapping(value = "/test/inst/", method = RequestMethod.POST)
public @ResponseBody ResponseDTO<InstDTO> 
        testPostREST(@RequestBody RequestDTO<InstDTO> instDTO) {

    RequestDTO<InstDTO> dto = new RequestDTO<InstDTO>();

    ResponseDTO<InstDTO> responseDto = new ResponseDTO<InstDTO>();
    responseDto.setPayload(instDTO.getPayload());
    return responseDto; 
}

with the following request object:

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class RequestDTO<T> {

    private List<T> payload;

    public RequestDTO() {
        System.out.println("constructor");
    }

    public RequestDTO(List<T> payload) {
        this.payload = payload;
    }

    public List<T> getPayload() {
        return payload;
    }

    public void setPayload(List<T> payload) {
        this.payload = payload;
    }
}

When the POST comes through and I look the object I get, the payload list has LinkedHashMap objects instead of objects of my DTO type.

How can I make spring+jackson convert the JSON into my DTO object. Bear in mind that I plan to reuse the wrapper ResponseDTO for other lists of objects and that's why I'm using a generic list (List).

Here's the JSON I'm trying.

{
  "payload": [
    {
      "d": "Test 0",
      "id": "abcde",
      "c": "Test 0"
    },
    {
      "d": "Test 1",
      "id": "123",
      "c": "Test 1"
    }
  ]
}

2条回答
淡お忘
2楼-- · 2019-07-24 18:57

If using Jackson isn't a requirement then you might want to consider using Gson instead.

You can tell Gson how to deserialize your json by just passing it a json string and the class that you want to deserialize. It would be pretty simple. I've included an example where I had to deserialize a response from a rest api below.

entity = response.getEntity();
jsonResponse = EntityUtils.toString(entity);
JsonNode root = mapper.readTree(jsonResponse).get("result");
returnedProduct = gson.fromJson(root.toString(),Product.class);
查看更多
Ridiculous、
3楼-- · 2019-07-24 19:00

Your code does not work due to type erasure. Jackson runtime does not know that you are trying to marshal the payload into InstitutionDTO objects (since this information has been erased at compile time). When Jackson looks at the payload, it sees valid JSON objects on the wire and a List<Object> on the Java side. It has no choice but to map the payload to a Map implementation, which in your case seems to be LinkedHashMap.

You may be able to achieve what you are looking for as follows:

class RequestDTO<T> {}
class ResponseDTO<T> {}
class InstitutionDTO {}
class InstitutionRequestDTO extends RequestDTO<InstitutionDTO>
class InstitutionResponseDTO extends ResponseDTO<InstitutionDTO>

@RequestMapping(value = "/test/institution/", method = RequestMethod.POST)
public @ResponseBody InstitutionResponseDTO
    testPostREST(@RequestBody InstitutionRequestDTO institutionDTO) { }

Disclaimer: I haven't tried this code myself but most of my applications have code similar to this and it works with Jackson, Castor, Atom, etc. without a glitch.

查看更多
登录 后发表回答