title: Restructure JSON before deserializing with Jackson
body: <p>We have a service which currently consumes JSON. We want to slightly restructure this JSON (move one property one level up) but also implement graceful migration so that our service could process old structure as well as new structure. We're using Jackson for JSON deserialization. </p>
  
  <p><strong>How do we restructure JSON prior to deserialization with Jackson?</strong></p>
  
  <p>Here's a MCVE.</p>
  
  <p>Assume our old JSON looks as follows:</p>
  
  <pre><code>{"reference": {"number" : "one", "startDate" : [2016, 11, 16], "serviceId" : "0815"}}
  </code></pre>
  
  <p>We want to move <code>serviceId</code> one level up:</p>
  
  <pre><code>{"reference": {"number" : "one", "startDate" : [2016, 11, 16]}, "serviceId" : "0815"}
  </code></pre>
  
  <p>This are the classes we want to deserialize from <em>both</em> old an new JSONs:</p>
  
  <pre><code>   public final static class Container {
  
          public final Reference reference;
  
          public final String serviceId;
  
          @JsonCreator
          public Container(@JsonProperty("reference") Reference reference, @JsonProperty("serviceId") String serviceId) {
              this.reference = reference;
              this.serviceId = serviceId;
          }
  
      }
  
      public final static class Reference {
  
          public final String number;
  
          public final LocalDate startDate;
  
          @JsonCreator
          public Reference(@JsonProperty("number") String number, @JsonProperty("startDate") LocalDate startDate) {
              this.number = number;
              this.startDate = startDate;
          }
      }
  </code></pre>
  
  <p>We only want <code>serviceId</code> in <code>Container</code>, not in both classes.</p>
  
  <p>What I've got working is the following deserializer:</p>
  
  <pre><code>public static class ServiceIdMigratingContainerDeserializer extends JsonDeserializer&lt;Container&gt; {
  
      private final ObjectMapper objectMapper;
  
      {
          objectMapper = new ObjectMapper();
          objectMapper.registerModule(new JavaTimeModule());
          objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
          objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
      }
  
      @Override
      public Container deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
          ObjectNode node = p.readValueAsTree();
          migrate(node);
          return objectMapper.treeToValue(node, Container.class);
      }
  
      private void migrate(ObjectNode containerNode) {
          TreeNode referenceNode = containerNode.get("reference");
          if (referenceNode != null &amp;&amp; referenceNode.isObject()) {
              TreeNode serviceIdNode = containerNode.get("serviceId");
              if (serviceIdNode == null) {
                  TreeNode referenceServiceIdNode = referenceNode.get("serviceId");
                  if (referenceServiceIdNode != null &amp;&amp; referenceServiceIdNode.isValueNode()) {
                      containerNode.set("serviceId", (ValueNode) referenceServiceIdNode);
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>This deserializer first retrieves the tree, manipulates it and then deserializers it using an own instance of <code>ObjectMapper</code>. It works but we really dislike the fact that we have another instance of <code>ObjectMapper</code> here. If we don't create it and somehow use the system-wide instance of <code>ObjectMapper</code> we get an infinite cycle because when we try to call <code>objectMapper.treeToValue</code>, our deserializer gets called recursively. So this works (with an own instance of <code>ObjectMapper</code>) but it is not an optimal solution.</p>
  
  <p>Another method I've tried was using a <code>BeanDeserializerModifier</code> and a own <code>JsonDeserializer</code> which "wraps" the default serializer:</p>
  
  <pre><code>public static class ServiceIdMigrationBeanDeserializerModifier extends BeanDeserializerModifier {
  
      @Override
      public JsonDeserializer&lt;?&gt; modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
              JsonDeserializer&lt;?&gt; defaultDeserializer) {
          if (beanDesc.getBeanClass() == Container.class) {
              return new ModifiedServiceIdMigratingContainerDeserializer((JsonDeserializer&lt;Container&gt;) defaultDeserializer);
          } else {
              return defaultDeserializer;
          }
      }
  }
  
  public static class ModifiedServiceIdMigratingContainerDeserializer extends JsonDeserializer&lt;Container&gt; {
  
      private final JsonDeserializer&lt;Container&gt; defaultDeserializer;
  
      public ModifiedServiceIdMigratingContainerDeserializer(JsonDeserializer&lt;Container&gt; defaultDeserializer) {
          this.defaultDeserializer = defaultDeserializer;
      }
  
      @Override
      public Container deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
          ObjectNode node = p.readValueAsTree();
          migrate(node);
          return defaultDeserializer.deserialize(new TreeTraversingParser(node, p.getCodec()), ctxt);
      }
  
      private void migrate(ObjectNode containerNode) {
          TreeNode referenceNode = containerNode.get("reference");
          if (referenceNode != null &amp;&amp; referenceNode.isObject()) {
              TreeNode serviceIdNode = containerNode.get("serviceId");
              if (serviceIdNode == null) {
                  TreeNode referenceServiceIdNode = referenceNode.get("serviceId");
                  if (referenceServiceIdNode != null &amp;&amp; referenceServiceIdNode.isValueNode()) {
                      containerNode.set("serviceId", (ValueNode) referenceServiceIdNode);
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>"Wrapping" a default deserializer seems to be a better approach, but this fails with an NPE:</p>
  
  <pre><code>java.lang.NullPointerException
      at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:157)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
      at de.db.vz.rikernpushadapter.migration.ServiceIdMigrationTest$ModifiedServiceIdMigratingContainerDeserializer.deserialize(ServiceIdMigrationTest.java:235)
      at de.db.vz.rikernpushadapter.migration.ServiceIdMigrationTest$ModifiedServiceIdMigratingContainerDeserializer.deserialize(ServiceIdMigrationTest.java:1)
      at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1623)
      at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1217)
      at ...
  </code></pre>
  
  <p>The whole MCVE code is in the following <a href="http://pastebin.com/Zee1Tqj0" rel="nofollow noreferrer">PasteBin</a>. It is a single-class all-containing test case which demonstrates both approaches. The <code>migratesViaDeserializerModifierAndUnmarshalsServiceId</code> fails.</p>
  
  <p>So this leaves me with a question:</p>
  
  <p><strong>How do we restructure JSON prior to deserialization with Jackson?</strong></p>