Fix pom file typo
[externalapi/nbi.git] / src / main / java / org / onap / nbi / commons / JacksonFilter.java
1 package org.onap.nbi.commons;
2
3 import java.math.BigDecimal;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collection;
7 import java.util.LinkedHashSet;
8 import java.util.LinkedList;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import org.springframework.util.LinkedMultiValueMap;
13 import org.springframework.util.MultiValueMap;
14 import com.fasterxml.jackson.databind.JsonNode;
15 import com.fasterxml.jackson.databind.ObjectMapper;
16 import com.fasterxml.jackson.databind.node.ArrayNode;
17 import com.fasterxml.jackson.databind.node.ObjectNode;
18
19 public class JacksonFilter {
20
21     private final static List<String> SKIPPED_FIELDS = Arrays.asList("internalId");
22
23
24     public static <R> List<ObjectNode> createNodes(List<R> list, JsonRepresentation jsonRepresentation) {
25
26         Set<R> set;
27         if (list == null) {
28             set = new LinkedHashSet<>();
29         } else {
30             set = new LinkedHashSet<>(list);
31         }
32         return createNodes(set, jsonRepresentation);
33     }
34
35     public static <R> List<ObjectNode> createNodes(Collection<R> collection, JsonRepresentation jsonRepresentation) {
36         List<ObjectNode> nodeList = new ArrayList<>();
37         for (R element : collection) {
38             ObjectNode node = createNode(element, jsonRepresentation);
39             nodeList.add(node);
40         }
41         return nodeList;
42     }
43
44     public static <R> ObjectNode createNode(R bean, JsonRepresentation jsonRepresentation) {
45         ObjectMapper mapper = new ObjectMapper();
46         return JacksonFilter.createNode(mapper, bean, jsonRepresentation.getAttributes());
47     }
48
49     private static <R> ObjectNode createNode(ObjectMapper mapper, R bean, Set<String> names) {
50         // split fieldNames in 2 categories :
51         // simpleFields for simple property names with no '.'
52         // nestedFields for nested property names with a '.'
53         Set<String> simpleFields = new LinkedHashSet<String>();
54         MultiValueMap nestedFields = new LinkedMultiValueMap();
55         buildFields(names, simpleFields, nestedFields);
56
57         // create a simple node with only one level containing all simples
58         // properties
59         ObjectNode rootNode = JacksonFilter.createNodeWithSimpleFields(mapper, bean, simpleFields);
60
61         // create nested nodes with deeper levels
62         Set<Map.Entry<String, List<String>>> entrySet = nestedFields.entrySet();
63         // for each nested value, create recursively a node
64         for (Map.Entry<String, List<String>> entry : entrySet) {
65             String rootFieldName = entry.getKey();
66             // add in current node only if full value is not already present in
67             // 1st level
68             if (!simpleFields.contains(rootFieldName)) {
69                 Object nestedBean = BeanUtils.getNestedProperty(bean, rootFieldName);
70                 // add only non null fields
71                 if (nestedBean == null) {
72                     continue;
73                 }
74                 Set<String> nestedFieldNames = new LinkedHashSet<String>(entry.getValue());
75                 // current node is an array or a list
76                 if ((nestedBean.getClass().isArray()) || (Collection.class.isAssignableFrom(nestedBean.getClass()))) {
77                     handleListNode(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
78                 } else {
79                     // create recursively a node and add it in current root node
80                     createNodeRecursively(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
81                 }
82             }
83         }
84         return rootNode;
85     }
86
87     private static void createNodeRecursively(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
88             Object nestedBean, Set<String> nestedFieldNames) {
89         ObjectNode nestedNode = JacksonFilter.createNode(mapper, nestedBean, nestedFieldNames);
90         if ((nestedNode != null) && (nestedNode.size() > 0)) {
91             rootNode.set(rootFieldName, nestedNode);
92         }
93     }
94
95     private static void buildFields(Set<String> names, Set<String> simpleFields, MultiValueMap nestedFields) {
96         for (String name : names) {
97             int index = name.indexOf('.');
98             boolean isNestedField = (index > 0) && (index < name.length());
99             if (isNestedField) {
100                 String rootFieldName = name.substring(0, index);
101                 String subFieldName = name.substring(index + 1);
102                 nestedFields.add(rootFieldName, subFieldName);
103             } else {
104                 simpleFields.add(name);
105             }
106         }
107     }
108
109     private static void handleListNode(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
110             Object nestedBean, Set<String> nestedFieldNames) {
111         Object[] array = null;
112         if ((nestedBean.getClass().isArray())) {
113             array = (Object[]) nestedBean;
114         } else {
115             Collection<?> collection = (Collection<?>) nestedBean;
116             array = collection.toArray();
117         }
118         if (array.length > 0) {
119             // create a node for each element in array
120             // and add created node in an arrayNode
121             Collection<JsonNode> nodes = new LinkedList<JsonNode>();
122             for (Object object : array) {
123                 ObjectNode nestedNode = JacksonFilter.createNode(mapper, object, nestedFieldNames);
124                 if ((nestedNode != null) && (nestedNode.size() > 0)) {
125                     nodes.add(nestedNode);
126                 }
127             }
128             ArrayNode arrayNode = mapper.createArrayNode();
129             arrayNode.addAll(nodes);
130             if (arrayNode.size() > 0) {
131                 rootNode.set(rootFieldName, arrayNode);
132             }
133         }
134     }
135
136     private static <R> ObjectNode createNodeWithSimpleFields(ObjectMapper mapper, R bean, Set<String> names) {
137         ObjectNode node = mapper.createObjectNode();
138         for (String name : names) {
139             // Prevent getting value of some fields
140             if (SKIPPED_FIELDS.contains(name)) {
141                 continue;
142             }
143
144             JacksonFilter.nodePut(node, name, BeanUtils.getNestedProperty(bean, name));
145         }
146         return node;
147     }
148
149     private static void nodePut(ObjectNode node, String name, Object value) {
150         if (value instanceof Boolean) {
151             node.put(name, (Boolean) value);
152         } else if (value instanceof Integer) {
153             node.put(name, (Integer) value);
154         } else if (value instanceof Long) {
155             node.put(name, (Long) value);
156         } else if (value instanceof Float) {
157             node.put(name, (Float) value);
158         } else if (value instanceof Double) {
159             node.put(name, (Double) value);
160         } else if (value instanceof BigDecimal) {
161             node.put(name, (BigDecimal) value);
162         } else if (value instanceof String) {
163             node.put(name, (String) value);
164         } else {
165             node.putPOJO(name, value);
166         }
167     }
168
169 }