Fixed JSON Deserializer to retain empty objects as empty rather than NULL.
[netvirt.git] / ovsdb / src / main / java / org / opendaylight / ovsdb / lib / notation / json / Converter.java
1 package org.opendaylight.ovsdb.lib.notation.json;
2
3 import org.opendaylight.ovsdb.lib.message.TableUpdates;
4 import org.opendaylight.ovsdb.lib.message.UpdateNotification;
5 import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
6 import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
7 import org.opendaylight.ovsdb.lib.notation.UUID;
8
9 import com.fasterxml.jackson.databind.DeserializationFeature;
10 import com.fasterxml.jackson.databind.JsonNode;
11 import com.fasterxml.jackson.databind.ObjectMapper;
12 import com.fasterxml.jackson.databind.util.StdConverter;
13
14 public class Converter {
15
16     static AtomDeser atomDeser = new AtomDeser();
17     static MapDeser mapDeser = new MapDeser();
18     static SetDeser setDeser = new SetDeser();
19     static UpdateNotificationDeser unDeser = new UpdateNotificationDeser();
20
21     public static class MapConverter extends StdConverter<JsonNode, OvsDBMap<Object, Object>> {
22         @Override
23         public OvsDBMap<Object, Object> convert(JsonNode value) {
24             return mapDeser.deserialize(value);
25         }
26     }
27
28     public static class SetConverter extends StdConverter<JsonNode, OvsDBSet<Object>> {
29         @Override
30         public OvsDBSet<Object> convert(JsonNode value) {
31             return setDeser.deserialize(value);
32         }
33     }
34
35     public static class UpdateNotificationConverter extends StdConverter<JsonNode, UpdateNotification> {
36         @Override
37         public UpdateNotification convert(JsonNode value) {
38             return unDeser.deserialize(value);
39         }
40     }
41
42     static class MapDeser {
43         public OvsDBMap<Object, Object> deserialize(JsonNode node) {
44             if (node.isArray()) {
45                 if (node.size() == 2) {
46                     if (node.get(0).isTextual() && "map".equals(node.get(0).asText())) {
47                         OvsDBMap<Object, Object> map = new OvsDBMap<Object, Object>();
48                         for (JsonNode pairNode : node.get(1)) {
49                             if (pairNode.isArray() && node.size() == 2) {
50                                 Object key = atomDeser.deserialize(pairNode.get(0));
51                                 Object value = atomDeser.deserialize(pairNode.get(1));
52                                 map.put(key, value);
53                             }
54                         }
55                         return map;
56                     } else if (node.size() == 0) {
57                         return null;
58                     }
59                 }
60             }
61             throw new RuntimeException("not a map type");
62         }
63     }
64
65     static class SetDeser {
66         public OvsDBSet<Object> deserialize(JsonNode node) {
67             OvsDBSet<Object> set = new OvsDBSet<Object>();
68             if (node.isArray()) {
69                 if (node.size() == 2) {
70                     if (node.get(0).isTextual() && "set".equals(node.get(0).asText())) {
71                         for (JsonNode atomNode : node.get(1)) {
72                             set.add(atomDeser.deserialize(atomNode));
73                         }
74                         return set;
75                     }
76                 } else if (node.size() == 0) {
77                     return null;
78                 }
79             }
80             //treat the whole thing as a single Atom
81             Object atom = atomDeser.deserialize(node);
82             if (null != atom) {
83                 set.add(atom);
84             }
85             return set;
86         }
87     }
88
89     static class UpdateNotificationDeser {
90         public UpdateNotification deserialize(JsonNode node) {
91             UpdateNotification un = new UpdateNotification();
92             if (node.isArray()) {
93                 if (node.size() == 2) {
94                     un.setContext(node.get(0).asText());
95                     ObjectMapper objectMapper = new ObjectMapper();
96                     objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
97                     TableUpdates updates = objectMapper.convertValue(node.get(1), TableUpdates.class);
98                     un.setUpdate(updates);
99                     return un;
100                 }
101             }
102             return null;
103         }
104     }
105
106     static class AtomDeser {
107
108         public Object deserialize(JsonNode node) {
109             if (!node.isArray()) {
110                 switch (node.getNodeType()) {
111                     case BOOLEAN:
112                         return node.asBoolean();
113                     case NUMBER:
114                         if (node.isFloatingPointNumber()) {
115                             return node.decimalValue();
116                         } else {
117                             return node.bigIntegerValue();
118                         }
119                     case STRING:
120                         return node.asText();
121                 }
122             }
123
124             if (node.isArray() && node.get(0).isTextual()) {
125                 if ("uuid".equals(node.get(0).asText()) || "named-uuid".equals(node.get(0).asText())) {
126                     return new UUID(node.get(1).asText());
127                 }
128             }
129
130             throw new RuntimeException("not an atom node");
131         }
132     }
133 }