6

I have some simple data in XML format which I need to convert to JSON and also be able to convert the JSON back into the same XML string. But I'm having problems with doing this using existing jackson (version 2.0.6) libraries.

Here's an example of XML data with similar structure

<channels>
  <channel>A</channel>
  <channel>B</channel>
  <channel>C</channel>
</channels>

To be able to convert this back to the original XML, I'd like the JSON to look something like this

{
  "channels": {
    "channel": [
      "A",
      "B",
      "C"
    ]
  }
}

However jackson gives me

{"channel":"C"}

The root element name is not preserved and instead og creating array of channels, the last one overwrites the previous ones.

Looking at the source code of com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer I found that the library doesn't support this, but allows for overriding and changing the behavior.

/**
 * Method called when there is a duplicate value for a field.
 * By default we don't care, and the last value is used.
 * Can be overridden to provide alternate handling, such as throwing
 * an exception, or choosing different strategy for combining values
 * or choosing which one to keep.
 *
 * @param fieldName Name of the field for which duplicate value was found
 * @param objectNode Object node that contains values
 * @param oldValue Value that existed for the object node before newValue
 *   was added
 * @param newValue Newly added value just added to the object node
 */
protected void _handleDuplicateField(String fieldName, ObjectNode objectNode,
                                     JsonNode oldValue, JsonNode newValue)
    throws JsonProcessingException
{
    // By default, we don't do anything
    ;
}

So my questions are

  1. Has anyone written a custom deserializer to support this feature? Or is there another way to work around this.
  2. How do I preserve the root element name?

Below is a test example

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Test {
  public static void main(String[] args) throws Exception {
    String xml="<channels><channel>A</channel><channel>B</channel><channel>C</channel></channels>";

    XmlMapper xmlMapper = new XmlMapper();
    JsonNode node=xmlMapper.readValue(xml,JsonNode.class);
    System.out.println(node.toString());
  }
}
alternative4
  • 148
  • 1
  • 2
  • 10
  • FWIW, _handleDuplicateField is NOT the way to do this -- it's simply an error handling thing. Also, you can't effectively use Tree Model for dealing with this -- XML databinding requires couple of work-arounds that can't be applied without type information that Java classes provide. – StaxMan Sep 14 '12 at 21:37
  • I figured I might be heading in the wrong direction. Thanks for clarifying this for me :) It's probably best for me to create some POJOs for the few variations I have to be able to serialize and de-serialize, at least until the jackson library has proper support for this in version 2.1. – alternative4 Sep 17 '12 at 09:30

1 Answers1

2

What really matters here are your classes -- just showing XML in itself does not give enough information to know what is going on.

I suspect that you will need Jackson 2.1 (once it gets released in a week or two), since it finally supports "unwrapped Lists" correectly. Prior to this, only "wrapped" Lists work correctly.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Ok thanks for your answer, I'll check the updated version when it's out. I'm just surprised that this isn't mentioned on the overview page for [jackson-dataformat-xml](https://github.com/FasterXML/jackson-dataformat-xml) – alternative4 Sep 17 '12 at 09:25
  • By the way, I forgot to mention I'm currently using version 2.0.6 of the jackson library (2.0.5 of jackson-dataformat-xml). – alternative4 Sep 17 '12 at 09:45
  • Agreed that intro page is incomplete -- lack of support for "unwrapped" arrays is one big thing that can easily bite anyone expecting full JAXB compatibility. – StaxMan Sep 17 '12 at 20:52