3

Working with restful api that returns a json string. The format is

{
  "status": "ok",
  "result": { <the method result> }
}

I am trying to map the response for user profile to UserProfile.class

MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
parameters.set("method", "currentUser");
URI url = buildUri("users/show.json");
UserProfile profile = this.getRestTemplate().postForObject(url, parameters, UserProfile.class );

User profile has all the fields from response result. if I add fields String status, UserProfile result, it maps the UserProfile to result and I can extract it from there, but that feels a little wrong.

I want postForObject function to map the JSON response relevant leaf "result" to UserProfile.class

L R
  • 45
  • 9

1 Answers1

2

To me the clearest approach would be to map the response result to an object which contains the user profile object. You would avoid unnecessary complication doing custom deserialization and allow you to access the status code. You could even make the response result object generic so it would work for any type of the content.

Here is an example using Jackon's object mapper. In Spring you would need to useParameterizedTypeReference to pass the generic type information (see this answer):

public class JacksonUnwrapped {

    private final static String JSON = "{\n" +
            "  \"status\": \"ok\",\n" +
            "  \"result\": { \"field1\":\"value\", \"field2\":123 }\n" +
            "}";


    public static class Result<T> {
        public final String status;
        public final T result;

        @JsonCreator
        public Result(@JsonProperty("status") String status,
                      @JsonProperty("result") T result) {
            this.status = status;
            this.result = result;
        }

        @Override
        public String toString() {
            return "Result{" +
                    "status='" + status + '\'' +
                    ", result=" + result +
                    '}';
        }
    }

    public static class UserProfile {
        public final String field1;
        public final int field2;

        @JsonCreator
        public UserProfile(@JsonProperty("field1") String field1,
                           @JsonProperty("field2") int field2) {
            this.field1 = field1;
            this.field2 = field2;
        }

        @Override
        public String toString() {
            return "UserProfile{" +
                    "field1='" + field1 + '\'' +
                    ", field2=" + field2 +
                    '}';
        }
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Result<UserProfile> value = mapper.readValue(JSON, new TypeReference<Result<UserProfile>>() {});
        System.out.println(value.result);
    }

}

Output:

UserProfile{field1='value', field2=123}
Community
  • 1
  • 1
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
  • How do I get the User, with a getter method from Result? I came up with something similar. The thing that bothers me that for getting other type of object, let's say UserSettings, I have to have another Result (like UserSettingsResult) class just with a different Type in param... And this for every postForObject() method. Looks too much repetition of code to accommodate every type. – L R Jun 15 '14 at 14:41
  • You could make the result object generic so it can accommodate any type of the content object. I've updated my answer to demonstrate how that could be done. – Alexey Gavrilov Jun 15 '14 at 18:09
  • It worked! I adapted it to my own version not to have nested classes, but ParameterizedTypeReference made it work! Just an alert to anyone doing this, Intellij gives you errors when evaluating in step debugging as it cannot analyze anonymous classes. Just hit f8 and see the result. – L R Jun 15 '14 at 21:37