Search code examples
javagenericsspring-bootjacksonresttemplate

Unable to make restTemplate call with Generics for nested Json


I am trying to make a restTemplate call for API testing. The json returned is a nested one with multiple levels.

{
  "code": 200,
  "data": {
    "result": {
      "publicId": "xyz"
    }
  }
}

I have the following classes acting as wrapper :

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public abstract class RestCallResponse<T> {

    private int code;

    protected RestCallResponse(int code) {
        this.code = code;
    }

    protected RestCallResponse(){}

    @JsonProperty("data")
    public Map<?, ?> getRestCallResponse() {
        return ImmutableMap.of("result", getResult());
    }

    @JsonIgnore
    protected abstract T getResult();

    public int getCode() {
        return code;
    }
}

And then a SuccessRestResponse class extending this abstract class :

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE)
public class SuccessRestResponse<T> extends RestCallResponse<T> {

    @JsonProperty("result")
    private T result;

    public SuccessRestResponse() {

    }

    public SuccessRestResponse(T result) {
        super(HttpStatus.SC_OK);
        this.result = result;
    }

    protected T getResult() {
        return this.result;
    }

}

Then finally I have the actual data POJO :

public final class CreatedResponse {
    @JsonProperty
    private final EntityId publicId;

    public CreateCreativeResponse(EntityId publicId) {
        this.publicId = publicId;
    }
}

In the test case, I am making a call as such :

ResponseEntity<SuccessRestResponse<CreatedResponse>> newResponse =
                restTemplate.exchange(requestEntity, new ParameterizedTypeReference<SuccessRestResponse<CreatedResponse>>() {});

But I am getting the following error :

nested exception is org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: null value in entry: result=null (through reference chain: com.inmobi.helix.test.api.dao.SuccessRestResponse["data"]);

Any suggestions? Where am I going wrong?


Solution

  • I solved the problem with a workaround. Still don't know what's wrong with the above piece of code though. I got rid of the class RestCallResponse<T> and edited the field members in SuccessRestResponse<T> to look like this :

    @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
    public class SuccessRestResponse<T> {
    
        private int code;
        private Map<String, T> data;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public Map<String, T> getData() {
            return data;
        }
    
        @JsonIgnore
        public T getResult() {
            return data.get("result");
        }
    
        public void setData(Map<String, T> data) {
            this.data = data;
        }
    }
    

    This corresponds to the nested json while deserialization.

    P.S. - Would still like to know what went wrong in my above code though. As in, why did class hierarchy not work for me.