jackson desearlization: two keys at root. how do i unwrap one and ignore the other?
Asked Answered
J

1

6

using jackson 2.x

the json response looks like this:

{
 "flag": true,
 "important": {
   "id": 123,
   "email": "[email protected]"
 }
}

The "flag" key does not provide any useful information. I would like to ignore the "flag" key and unwrap the "important" value to an instance of Important.

public class Important {

    private Integer id;
    private String email;

    public Important(@JsonProperty("id") Integer id,
                     @JsonProperty("email") String email) {
        this.id = id;
        this.email = email;
    }

    public String getEmail() { this.email }

    public Integer getId() { this.id }
}

When I try to add a @JsonRootName("important") to Important and configure the ObjectMapper with DeserializationFeature.UNWRAP_ROOT_VALUE I receive a JsonMappingException:

Root name 'flag' does not match expected ('important') for type ...

When i remove the "flag" key/value from the JSON the data binding works just fine. I get the same result if i add @JsonIgnoreProperties("flag") to Important as well.

UPDATES


updated class ... that will actually pass the compile step
@JsonRootName("important")
public static class Important {
    private Integer id;
    private String email;

    @JsonCreator
    public Important(@JsonProperty("id") Integer id,
                     @JsonProperty("email") String email) {
        this.id = id;
        this.email = email;
    }

    public String getEmail() { return this.email; }

    public Integer getId() { return this.id; }
}

actual test:

@Test
public void deserializeImportant() throws IOException {
    ObjectMapper om = new ObjectMapper();
    om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    om.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
    Important important = om.readValue(getClass().getResourceAsStream("/important.json"), Important.class);

    assertEquals((Integer)123, important.getId());
    assertEquals("[email protected]", important.getEmail());
}

results:

com.fasterxml.jackson.databind.JsonMappingException: Root name 'flag' does not match expected ('important') for type [simple type, class TestImportant$Important]

Jurgen answered 15/9, 2014 at 21:14 Comment(0)
W
2

Just because of streaming nature of JSON parsing in Jackson, I'm afraid there is no easy way of handling such cases.

From my point of view, it's easier to do with some sort of wrapper.

Consider this code:

public static class ImportantWrapper {
    @JsonProperty("important")
    private Important important;

    public Important getImportant() {
        return important;
    }
}

And actual test:

@Test
public void deserializeImportant() throws IOException {
    ObjectMapper om = new ObjectMapper();
    //note: this has to be present
    om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    Important important = om.readValue(getClass().getResourceAsStream("/important.json"), ImportantWrapper.class)
                                .getImportant();

    assertEquals((Integer)123, important.getId());
    assertEquals("[email protected]", important.getEmail());
}

Note, that @JsonRootName("important") is redundant and can be removed in this case.

This looks some sort of ugly, but works perfectly with relatively small effort. Also such "wrappers" can be generified, but this is more like architecture's stuff.

Wiper answered 17/9, 2014 at 11:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.