1 package org.onap.nbi.commons;
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;
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;
19 public class JacksonFilter {
21 private final static List<String> SKIPPED_FIELDS = Arrays.asList("internalId");
24 public static <R> List<ObjectNode> createNodes(List<R> list, JsonRepresentation jsonRepresentation) {
28 set = new LinkedHashSet<>();
30 set = new LinkedHashSet<>(list);
32 return createNodes(set, jsonRepresentation);
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);
44 public static <R> ObjectNode createNode(R bean, JsonRepresentation jsonRepresentation) {
45 ObjectMapper mapper = new ObjectMapper();
46 return JacksonFilter.createNode(mapper, bean, jsonRepresentation.getAttributes());
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);
57 // create a simple node with only one level containing all simples
59 ObjectNode rootNode = JacksonFilter.createNodeWithSimpleFields(mapper, bean, simpleFields);
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
68 if (!simpleFields.contains(rootFieldName)) {
69 Object nestedBean = BeanUtils.getNestedProperty(bean, rootFieldName);
70 // add only non null fields
71 if (nestedBean == null) {
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);
79 // create recursively a node and add it in current root node
80 createNodeRecursively(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
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);
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());
100 String rootFieldName = name.substring(0, index);
101 String subFieldName = name.substring(index + 1);
102 nestedFields.add(rootFieldName, subFieldName);
104 simpleFields.add(name);
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;
115 Collection<?> collection = (Collection<?>) nestedBean;
116 array = collection.toArray();
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);
128 ArrayNode arrayNode = mapper.createArrayNode();
129 arrayNode.addAll(nodes);
130 if (arrayNode.size() > 0) {
131 rootNode.set(rootFieldName, arrayNode);
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)) {
144 JacksonFilter.nodePut(node, name, BeanUtils.getNestedProperty(bean, name));
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);
165 node.putPOJO(name, value);