{"id":2297,"date":"2017-03-03T12:16:30","date_gmt":"2017-03-03T10:16:30","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=2297"},"modified":"2017-03-03T12:16:30","modified_gmt":"2017-03-03T10:16:30","slug":"domino-rest-more-about-jackson","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=2297","title":{"rendered":"Domino &#038; REST: More about Jackson"},"content":{"rendered":"<p style=\"text-align: left;\">When creating a REST API servlet,\u00a0Jackson provides a huge list of possibilities to manipulate the JSON data, mostly using annotations.<\/p>\n<p>Let&#8217;s demonstrate some of them with this\u00a0little class, which has only two properties:<\/p>\n<pre><code>public class Demo {\r\n\r\n    private String foo;\r\n<\/code><code>    private String bar;\r\n\r\n<\/code><code>    public String getFoo() { \r\n        return foo;\r\n    }\r\n    public void setFoo(String foo) {\r\n        this.foo = foo;\r\n    }\r\n\r\n<\/code><code>    public String getBar() { \r\n        return bar;\r\n    }\r\n\r\n    public void setBar(String bar) {\r\n        this.bar = bar;\r\n    }<\/code><code>\r\n}<\/code><\/pre>\n<p>The playground converts the <em>content<\/em>\u00a0string to a POJO and back to a string:<\/p>\n<pre><code>String content = \"{ \\\"foo\\\": \\\"bar\\\" }\";\r\n \r\n \/\/ init the ObjectMapper\r\n ObjectMapper mapper = new ObjectMapper();\r\n \r\n \/\/ build the Object\r\n Demo test = null;\r\n try {\r\n     test = mapper.readValue(content, Demo.class);\r\n } catch (Exception e) {\r\n     e.printStackTrace();\r\n }\r\n\r\n \/\/ and now convert it back to a String\r\n String data = null;\r\n try {\r\n     data = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(test);\r\n } catch (Exception e) {\r\n     e.printStackTrace();\r\n }\r\n\r\n System.out.println( data );<\/code><\/pre>\n<p>If we run this code, the result is not really spectacular:<\/p>\n<pre><code>{\r\n \"foo\" : \"bar\",\r\n \"bar\" : null\r\n}<\/code><\/pre>\n<p>So let&#8217;s ignore the property foo by adding the annotation <em>@JsonIgnoreProperties<\/em> to the <em>Demo<\/em> class:<\/p>\n<pre><code>@JsonIgnoreProperties({\"foo\"})\r\npublic class Demo { ... }<\/code><\/pre>\n<p>Now, <em>foo<\/em> is no longer in our resulting JSON:<\/p>\n<pre><code>{\r\n    \"bar\" : null\r\n}<\/code><\/pre>\n<p>The property <em>bar<\/em> is null, and we don&#8217;t like nulled properties in our JSON. That&#8217;s why we add another annotation, <em>@JsonInclude<\/em>:<\/p>\n<pre><code>@JsonInclude(JsonInclude.Include.NON_EMPTY)\r\npublic class Demo { ... }<\/code><\/pre>\n<p>After removing the previously added <em>@JsonIgnoreProperties<\/em> annotation, our result looks like this (the empty property <em>bar<\/em> was skipped):<\/p>\n<pre><code>{\r\n    \"foo\" : \"bar\"\r\n}<\/code><\/pre>\n<p>What happens if we change our <em>content<\/em> string, and add an unknown property?<\/p>\n<pre><code>String content = \"{ \\\"foo\\\": \\\"bar\\\", \\\"undefined\\\": \\\"property\\\" }\";<\/code><\/pre>\n<p>An error occurs because Jackson does not know how to handle the new property:<\/p>\n<pre><code>com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field \"undefined\" (class ch.hasselba.JacksonPlayground.Demo), not marked as ignorable (2 known properties: \"foo\", \"bar\"])\r\n at [Source: { \"foo\": \"bar\", \"undefined\": \"property\" }; line: 1, column: 31] (through reference chain: ch.hasselba.JacksonPlayground.Demo[\"undefined\"])\r\n at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)\r\n at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:817)\r\n at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:954)\r\n at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1315)\r\n at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1293)\r\n at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:249)\r\n at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)\r\n at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)\r\n at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2576)\r\n at ch.hasselba.JacksonPlayground.App.main(App.java:24)\r\nnull<\/code><\/pre>\n<p>But there are two annotations to the rescue, <em>@JsonAnyGetter<\/em> &amp;\u00a0<em>@JsonAnySetter<\/em>. By changing our <em>Demo<\/em> class and adding the following lines of code&#8230;<\/p>\n<pre><code>private Map&lt;String, Object&gt; others = new ConcurrentHashMap&lt;String, Object&gt;();\r\n\r\n@JsonAnyGetter\r\npublic Map&lt;String, Object&gt; getOthers() {\r\n    return this.others;\r\n}\r\n\r\n@JsonAnySetter\r\npublic void addOther(final String name, final Object value) {\r\n    this.others.put(name, value);\r\n}<\/code><\/pre>\n<p>&#8230; Jackson now puts all the unknown\/undefined properties in the <em>others<\/em> map (uses the method defined by <em>@JsonSetter<\/em>). And then it uses the method with the <em>@JsonGetter<\/em> annotation when producing the JSON from the Demo instance.<\/p>\n<pre><code>{\r\n  \"foo\" : \"bar\",\r\n  \"bar\" : null,\r\n  \"undefined\" : \"property\"\r\n}\r\n<\/code><\/pre>\n<p>What if we want to handle multiple &#8222;Demo&#8220; objects in a JSON Array?<\/p>\n<pre><code>String content = \"[ { \\\"foo\\\": \\\"bar\\\" }, {\\\"foo\\\": \\\"bar2\\\" } ]\";<\/code><\/pre>\n<p>In this case we change our reading routine to work with lists:<\/p>\n<pre><code>\/\/ build the Object\r\nList&lt;Demo&gt; test = null;\r\ntry {\r\n    test = mapper.readValue(content, mapper.getTypeFactory()\r\n            .constructCollectionType(List.class, Demo.class));\r\n} catch (Exception e) {\r\n    e.printStackTrace();\r\n}<\/code><\/pre>\n<p>In the result all entries are now contained in the list of <em>Demo<\/em>\u00a0objects:<\/p>\n<pre><code>[ {\r\n \"foo\" : \"bar\",\r\n \"bar\" : null\r\n}, {\r\n \"foo\" : \"bar2\",\r\n \"bar\" : null\r\n} ]<\/code><\/pre>\n<p>Back to our\u00a0<a href=\"https:\/\/github.com\/hasselbach\/domino-rest-servlet\/blob\/master\/domino-rest-servlet.plugin\/src\/ch\/hasselba\/dominorestservlet\/RestApiApplication.java\" target=\"_blank\">RestApiApplication<\/a>, have a look at this line:<\/p>\n<pre><code>objMapper.setSerializationInclusion(Include.NON_EMPTY);<\/code><\/pre>\n<p>This removes all empty properties globally from the generated output of our the servlet. So there is no need to add the <em>@JsonIgnore<\/em> annotation to any class. You can modifiy the globally used ObjectMapper in your servlet with multiple option, more will follow in another blog post.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When creating a REST API servlet,\u00a0Jackson provides a huge list of possibilities to manipulate the JSON data, mostly using annotations. Let&#8217;s demonstrate some of them with this\u00a0little class, which has only two properties: public class Demo { private String foo; &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=2297\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[120,114,116,61],"tags":[118,7,115,60,12],"class_list":["post-2297","post","type-post","status-publish","format-standard","hentry","category-apache-wink","category-jackson","category-jee","category-rest","tag-apache-wink","tag-domino","tag-jackson","tag-rest","tag-web"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2297","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2297"}],"version-history":[{"count":9,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2297\/revisions"}],"predecessor-version":[{"id":2334,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2297\/revisions\/2334"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}