How to skip wrapper object in jackson json deserialization How to skip wrapper object in jackson json deserialization json json

How to skip wrapper object in jackson json deserialization


You can create a custom annotation with @JsonDeserialize inside and create a custom JsonDeserializer that implements ContextualDeserializer. The idea is inspired from the solution you mentioned but it is more general to unwrap any one property in a json object.

Following is the custom annotation using @JacksonAnnotationsInside as annotation container contains @JsonDeserialize:

@Retention(RetentionPolicy.RUNTIME)@JacksonAnnotationsInside@JsonDeserialize(using = JsonUnwrapPropertyDeserializer.class)public @interface JsonUnwrapProperty {}

and the custom JsonDeserializer that implements ContextualDeserializer:

public class JsonUnwrapPropertyDeserializer extends JsonDeserializer<Object> implements ContextualDeserializer {    private JavaType unwrappedJavaType;    private String unwrappedProperty;    @Override    public JsonDeserializer<?> createContextual(final DeserializationContext deserializationContext, final BeanProperty beanProperty) throws JsonMappingException {        unwrappedProperty = beanProperty.getMember().getName();        unwrappedJavaType = beanProperty.getType();        return this;    }    @Override    public Object deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {        final TreeNode targetObjectNode = jsonParser.readValueAsTree().get(unwrappedProperty);        return jsonParser.getCodec().readValue(targetObjectNode.traverse(), unwrappedJavaType);    }}

and the usage example:

public class MyBean {    @JsonProperty("broadcastPresenceRoles")    @JsonUnwrapProperty    private List<String> broadcastPresenceRole;    @JsonProperty("admins")    @JsonUnwrapProperty    private String admin;    // constructor, getter and setter}

@JsonProperty is to locate the wrapper object and @JsonUnwrappProperty is to deserialize the json object and extract a property into the annotated field.

Edited:

Following is an example with ObjectMapper:

String json = "{\n" +        "  \"broadcastPresenceRoles\": {\n" +        "    \"broadcastPresenceRole\": [\n" +        "      \"moderator\",\n" +        "      \"participant\",\n" +        "      \"visitor\"\n" +        "    ]\n" +        "  },\n" +        "  \"admins\": {\n" +        "    \"admin\": \"sanjeet@shahanshah\"\n" +        "  }\n" +        "}";final ObjectMapper mapper = new ObjectMapper();final MyBean myBean = mapper.readValue(json, MyBean.class);System.out.println(myBean.getBroadcastPresenceRole());System.out.println(myBean.getAdmin());

Output:

[moderator, participant, visitor]

sanjeet@shahanshah


I created a variation that solved the NPE based on @wilson response

import java.io.IOException;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;import com.fasterxml.jackson.core.JsonParser;import com.fasterxml.jackson.core.JsonToken;import com.fasterxml.jackson.databind.BeanProperty;import com.fasterxml.jackson.databind.DeserializationContext;import com.fasterxml.jackson.databind.JavaType;import com.fasterxml.jackson.databind.JsonDeserializer;import com.fasterxml.jackson.databind.JsonMappingException;import com.fasterxml.jackson.databind.annotation.JsonDeserialize;import com.fasterxml.jackson.databind.deser.ContextualDeserializer;@Retention(RetentionPolicy.RUNTIME)@JacksonAnnotationsInside@JsonDeserialize(using = JsonUnwrapProperty.JsonUnwrapPropertyDeserializer.class)public @interface JsonUnwrapProperty {  public static class JsonUnwrapPropertyDeserializer extends JsonDeserializer<Object>      implements ContextualDeserializer {    private JavaType unwrappedJavaType;    private String unwrappedProperty;    @Override    public JsonDeserializer<?> createContextual(final DeserializationContext deserializationContext,        final BeanProperty beanProperty) throws JsonMappingException {      unwrappedProperty = beanProperty.getMember().getName();      unwrappedJavaType = beanProperty.getType();      return this;    }    @Override    public Object deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext)        throws IOException {      System.out.println(String.format("Ignoring %s in %s/%s", unwrappedProperty,        jsonParser.currentName(), jsonParser.nextFieldName()));      JsonToken token = jsonParser.nextValue();      return jsonParser.getCodec().readValue(jsonParser, unwrappedJavaType);    }  }}