title: Jackson Serialization: Different formats for XML and JSON
body: <p>I use Jackson to serialize/deserialize my application's model into both JSON and XML (need them both). </p>
  
  <p>Model classes:</p>
  
  <pre><code>@JacksonXmlRootElement
  public class Data { 
      @JsonProperty("attributes")
      @JsonDeserialize(using = AttributesDeserializer.class)
      @JsonSerialize(using = AttributesSerializer.class)
      @JacksonXmlElementWrapper
      private Map&lt;Key, Map&lt;String, Attribute&gt;&gt; attributes;
  </code></pre>
  
  <p>....</p>
  
  <pre><code>public class Key {
          private Integer id;
          private String name;
  </code></pre>
  
  <p>....</p>
  
  <pre><code>public class Attribute {
      private Integer id;
      private Integer value;
      private String name;
  </code></pre>
  
  <p>I need my JSON to look like this:</p>
  
  <pre><code> {
    "attributes": [
      {
        "key": {
          "id": 10,
          "name": "key1"
        },
        "value": {
          "numeric": {
            "id": 1,
            "value": 100,
            "name": "numericAttribute"
          },
          "text": {
            "id": 2,
            "value": 200,
            "name": "textAttribute"
          }
        }
      },
      {
        "key": {
          "id": 20,
          "name": "key2"
        },
        "value": {
          "numeric": {
            "id": 1,
            "value": 100,
            "name": "numericAttribute"
          },
          "text": {
            "id": 2,
            "value": 200,
            "name": "textAttribute"
          }
        }
      }
    ]
  }
  </code></pre>
  
  <p>And my XML something like this:</p>
  
  <pre><code>&lt;Data&gt;
      &lt;attributes&gt;
          &lt;key&gt;
              &lt;id&gt;10&lt;/id&gt;
              &lt;name&gt;key1&lt;/name&gt;
          &lt;/key&gt;
          &lt;value&gt;
              &lt;numeric&gt;
                  &lt;id&gt;1&lt;/id&gt;
                  &lt;value&gt;100&lt;/value&gt;
                  &lt;name&gt;numericAttribute&lt;/name&gt;
              &lt;/numeric&gt;
              &lt;text&gt;
                  &lt;id&gt;2&lt;/id&gt;
                  &lt;value&gt;200&lt;/value&gt;
                  &lt;name&gt;textAttribute&lt;/name&gt;
              &lt;/text&gt;
          &lt;/value&gt;
          &lt;key&gt;
              &lt;id&gt;20&lt;/id&gt;
              &lt;name&gt;key2&lt;/name&gt;
          &lt;/key&gt;
          &lt;value&gt;
              &lt;numeric&gt;
                  &lt;id&gt;1&lt;/id&gt;
                  &lt;value&gt;100&lt;/value&gt;
                  &lt;name&gt;numericAttribute&lt;/name&gt;
              &lt;/numeric&gt;
              &lt;text&gt;
                  &lt;id&gt;2&lt;/id&gt;
                  &lt;value&gt;200&lt;/value&gt;
                  &lt;name&gt;textAttribute&lt;/name&gt;
              &lt;/text&gt;
          &lt;/value&gt;
      &lt;/attributes&gt;
  &lt;/Data&gt;
  </code></pre>
  
  <p>I am obtaining both the required JSON and XML with the custom serializer:</p>
  
  <pre><code>public class AttributesSerializer extends JsonSerializer&lt;Map&lt;Key, Map&lt;String, Attribute&gt;&gt;&gt; {
  
      @Override
      public void serialize(Map&lt;Key, Map&lt;String, Attribute&gt;&gt; map, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
          jsonGenerator.writeStartArray();
          for (Map.Entry&lt;Key, Map&lt;String, Attribute&gt;&gt; entry : map.entrySet()) {
              jsonGenerator.writeStartObject();
              jsonGenerator.writeObjectField("key", entry.getKey());
              jsonGenerator.writeObjectFieldStart("value");
              for (Map.Entry&lt;String, Attribute&gt; attributesEntry : entry.getValue().entrySet()) {
                  jsonGenerator.writeObjectField(attributesEntry.getKey(), attributesEntry.getValue());
              }
              jsonGenerator.writeEndObject();
              jsonGenerator.writeEndObject();
          }
          jsonGenerator.writeEndArray();
      }
  }
  </code></pre>
  
  <p>And the deserialization works fine for the JSON with the custom deserializer:</p>
  
  <pre><code>public class AttributesDeserializer extends JsonDeserializer&lt;Map&lt;Key, Map&lt;String, Attribute&gt;&gt;&gt; {
      @Override
      public Map&lt;Key, Map&lt;String, Attribute&gt;&gt; deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
          JsonNode node = jsonParser.getCodec().readTree(jsonParser);
          if (node.size() == 0) {
              return null;
          }
          ObjectMapper om = new ObjectMapper();
          Map&lt;Key, Map&lt;String, Attribute&gt;&gt; attributes = new HashMap&lt;&gt;();
          node.forEach(jsonNode -&gt; {
              Map&lt;String, Attribute&gt; attributesMap = new HashMap&lt;&gt;();
              JsonNode keyNode = jsonNode.get("key");
              Key key = om.convertValue(keyNode, Key.class);
              JsonNode valueNode = jsonNode.get("value");
              Iterator&lt;Map.Entry&lt;String, JsonNode&gt;&gt; attributesIterator = valueNode.fields();
              while(attributesIterator.hasNext()) {
                  Map.Entry&lt;String, JsonNode&gt; field = attributesIterator.next();
                  Attribute attribute = om.convertValue(field.getValue(), Attribute.class);
                  attributesMap.put(field.getKey(), attribute);
              }
              attributes.put(key, attributesMap);
          });
  
  
          return attributes;
      }
  }
  </code></pre>
  
  <p>While everything is fine for the JSON, for the XML the application crashes in the deserialization:</p>
  
  <pre><code>Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: ro.alexsvecencu.jackson.Data["attributes"])
      at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
      at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
      at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1599)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2740)
      at ro.alexsvecencu.jackson.Main.main(Main.java:27)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:483)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
  Caused by: java.lang.NullPointerException
      at ro.alexsvecencu.jackson.AttributesDeserializer.lambda$deserialize$0(AttributesDeserializer.java:29)
      at ro.alexsvecencu.jackson.AttributesDeserializer$$Lambda$1/1709366259.accept(Unknown Source)
      at java.lang.Iterable.forEach(Iterable.java:75)
      at ro.alexsvecencu.jackson.AttributesDeserializer.deserialize(AttributesDeserializer.java:24)
      at ro.alexsvecencu.jackson.AttributesDeserializer.deserialize(AttributesDeserializer.java:15)
      at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
      at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
      ... 9 more
  </code></pre>
  
  <p>What's happening is that my custom deserializer crashes for the XML, because obviously it's not interpreting all the attributes as an 'array' and when I'm going through the jsonNode's children it will iterate through the keys/values. Also, through debugging I notice that the deserializer is just called for the LAST tag of attributes from XML.</p>
  
  <p><strong>Is there any way to tell Jackson to use specific custom deserializers/serializers that are different for XML and JSON?</strong> That's one way in which I think this could be solved.</p>
  
  <p>My XML could be formatted a bit different (I'm not really constrained in it's form, but the JSON has to keep that format). With this flexibility, do you see any alternative to solving my issue? I could just use something different for XML, like JAXB, but I'm pretty much constrained to use Jackson for both.</p>