Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson json deserialization, ignore root element from json

Tags:

json

jackson

How to ignore parent tag from json??

Here is my json

String str = "{\"parent\": {\"a\":{\"id\": 10, \"name\":\"Foo\"}}}"; 

And here is the class to be mapped from json.

public class RootWrapper {   private List<Foo> foos;    public List<Foo> getFoos() {     return foos;   }    @JsonProperty("a")   public void setFoos(List<Foo> foos) {     this.foos = foos;   }  } 

Here is the test public class JacksonTest {

@Test public void wrapRootValue() throws Exception {     ObjectMapper mapper = new ObjectMapper();     mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);     mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);      String str = "{\"parent\": {\"a\":{\"id\": 10, \"name\":\"Foo\"}}}";      RootWrapper root = mapper.readValue(str, RootWrapper.class);      Assert.assertNotNull(root); } 

I get the error ::

 org.codehaus.jackson.map.JsonMappingException: Root name 'parent' does not match expected ('RootWrapper') for type [simple type, class MavenProjectGroup.mavenProjectArtifact.RootWrapper] 

I found the solution given by Jackson annotation::

  (a) Annotate you class as below    @JsonRootName(value = "parent")   public class RootWrapper {    (b) It will only work if and only if ObjectMapper is asked to wrap.     ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true); 

Job Done!!

Another hiccup with Jackson way of Deserialization :(

if 'DeserializationConfig.Feature.UNWRAP_ROOT_VALUE configured', it unwrap all jsons, eventhough my class in not annotated with @JsonRootName(value = "rootTagInJson"), isn't weired.

I want to unwrap root tag only if the class is annotated with @JsonRootName otherwise, don't unwrap.

So below is the usecase for unwrap root tag.

  ###########################################################      Unwrap only if the class is annotated with @JsonRootName.   ############################################################ 

I did a small change in ObjectMapper of Jackson source code and created a new version of jar. 1. Place this method in ObjectMapper

// Ash:: Wrap json if the class being deserialized, are annotated // with @JsonRootName else do not wrap. private boolean hasJsonRootName(JavaType valueType) {     if (valueType.getRawClass() == null)         return false;      Annotation rootAnnotation =  valueType.getRawClass().getAnnotation(JsonRootName.class);     return rootAnnotation != null; }       2. Edit ObjectMapper method ::      Replace         cfg.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE)     with        hasJsonRootName(valueType)      3. Build your jar file and use it. 
like image 792
Ash Avatar asked Jan 12 '12 14:01

Ash


People also ask

How do I ignore a root element in JSON?

How to ignore parent tag from json?? String str = "{\"parent\": {\"a\":{\"id\": 10, \"name\":\"Foo\"}}}"; And here is the class to be mapped from json. (a) Annotate you class as below @JsonRootName(value = "parent") public class RootWrapper { (b) It will only work if and only if ObjectMapper is asked to wrap.

How do I exclude fields in JSON?

If there are fields in Java objects that do not wish to be serialized, we can use the @JsonIgnore annotation in the Jackson library. The @JsonIgnore can be used at the field level, for ignoring fields during the serialization and deserialization.

What is @JsonRootName?

@JsonRootName allows to have a root node specified over the JSON. We need to enable wrap root value as well.


2 Answers

An example taken from TestRootName.java in https://github.com/FasterXML/jackson-databind may give a better way of doing this. Specifically using withRootName(""):

private ObjectMapper rootMapper() {     ObjectMapper mapper = new ObjectMapper();     mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);     mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);     return mapper; }  public void testRootUsingExplicitConfig() throws Exception {     ObjectMapper mapper = new ObjectMapper();     ObjectWriter writer = mapper.writer().withRootName("wrapper");     String json = writer.writeValueAsString(new Bean());     assertEquals("{\"wrapper\":{\"a\":3}}", json);      ObjectReader reader = mapper.reader(Bean.class).withRootName("wrapper");     Bean bean = reader.readValue(json);     assertNotNull(bean);      // also: verify that we can override SerializationFeature as well:     ObjectMapper wrapping = rootMapper();     json = wrapping.writer().withRootName("something").writeValueAsString(new Bean());     assertEquals("{\"something\":{\"a\":3}}", json);     json = wrapping.writer().withRootName("").writeValueAsString(new Bean());     assertEquals("{\"a\":3}", json);      bean = wrapping.reader(Bean.class).withRootName("").readValue(json);     assertNotNull(bean); } 
like image 117
benathon Avatar answered Sep 23 '22 18:09

benathon


I experienced a similar problem developing a restful application in Spring. I had to support a very heterogeneous API, some of it had root elements, another did not. I could not find a better solution than to configure this property realtime. It's a great pity there is no support for per-class root element unwrapping in Jackson. Anyway, somebody may find this helpful.

@Component public class ObjectMapper extends com.fasterxml.jackson.databind.ObjectMapper {     private void autoconfigureFeatures(JavaType javaType) {         Annotation rootAnnotation = javaType.getRawClass().getAnnotation(JsonRootName.class);         this.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, rootAnnotation != null);     }      @Override     protected Object _readMapAndClose(JsonParser jsonParser, JavaType javaType) throws IOException, JsonParseException, JsonMappingException {         autoconfigureFeatures(javaType);         return super._readMapAndClose(jsonParser, javaType);     }  } 
like image 35
Segabond Avatar answered Sep 24 '22 18:09

Segabond