Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Jackson serializer for a generic tree

Say I have a parametrized tree implemented in Java as follows:

public class Tree<E> {
   private static class Node {
      E element;
      List<Node> children.
   }

   Node root;

   //... You get the idea.
}

The idea here is that the implementation above is only concerned with the topology of the tree, but does not know anything about the elements that will be stored in the tree by an instantiation.

Now, say I want my tree elements to be geographies. The reason they are organized in trees is because continents contain countries, countries contain states or a provinces, and so on. For simplicity, a geography has a name and a type:

public class GeoElement { String name; String type; }

So that, finally, the geo hierarchy looks like so:

public class Geography extends Tree<GeoElement> {}

Now to Jackson serialization. Assuming the Jackson serializer can see the fields, the direct serialization of this implementation will look like this:

{
   "root": {
      "element": {
         "name":"Latin America",
         "type":"Continent"
      }
      "children": [
          {
             "element": {
                "name":"Brazil",
                "type":"Country"
             },
             "children": [
                 // ... A list of states in Brazil
             ]
          },
          {
             "element": {
                "name":"Argentina",
                "type":"Country"
             },
             "children": [
                 // ... A list of states in Argentina
             ]
          }
      ]
   }

This JSON rendering is no good because it contains the unnecessary artifacts from the Tree and Node classes, i.e. "root" and "element". What I need instead is this:

{
   "name":"Latin America",
   "type":"Continent"
   "children": [
       {
          "name":"Brazil",
          "type":"Country"
          "children": [
             // ... A list of states in Brazil
          ]
       },
       {
          "name":"Argentina",
          "type":"Country"
          "children": [
             // ... A list of states in Argentina
          ]
       }
   ]
}

Any help is most appreciated. -Igor.

like image 681
Forelight Avatar asked Jan 28 '13 04:01

Forelight


2 Answers

What you need is @JsonUnwrapped.

Annotation used to indicate that a property should be serialized "unwrapped"; that is, if it would be serialized as JSON Object, its properties are instead included as properties of its containing Object

Add this annotation to the root field of Tree & element field of Node classes as follows:

public class Tree<E> {
   private static class Node {

      @JsonUnwrapped
      E element;
      List<Node> children.
   }

   @JsonUnwrapped
   Node root;

   //... You get the idea.
}

And it will give you your desired output:

{
    "name": "Latin America",
    "type": "Continent",
    "children": [{
        "name": "Brazil",
        "type": "Country",
        "children": []
    }, {
        "name": "Argentina",
        "type": "Country",
        "children": []
    }]
}
like image 129
Pankaj Singhal Avatar answered Nov 02 '22 10:11

Pankaj Singhal


Perhaps use @JsonValue like so:

public class Tree<E> {
  @JsonValue
  Node root;
}

if all you need is to just "unwrap" your tree?

like image 5
StaxMan Avatar answered Nov 02 '22 11:11

StaxMan