2 * Copyright (c) 2018 Orange
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.onap.nbi.commons;
18 import com.fasterxml.jackson.databind.MappingJsonFactory;
19 import java.math.BigDecimal;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.LinkedHashSet;
24 import java.util.LinkedList;
25 import java.util.List;
28 import org.springframework.util.LinkedMultiValueMap;
29 import org.springframework.util.MultiValueMap;
30 import com.fasterxml.jackson.databind.JsonNode;
31 import com.fasterxml.jackson.databind.ObjectMapper;
32 import com.fasterxml.jackson.databind.node.ArrayNode;
33 import com.fasterxml.jackson.databind.node.ObjectNode;
35 public class JacksonFilter {
37 private static final List<String> SKIPPED_FIELDS = Arrays.asList("internalId");
39 private JacksonFilter() {
42 public static <R> List<ObjectNode> createNodes(List<R> list, JsonRepresentation jsonRepresentation) {
46 set = new LinkedHashSet<>();
48 set = new LinkedHashSet<>(list);
50 return createNodes(set, jsonRepresentation);
53 public static <R> List<ObjectNode> createNodes(Collection<R> collection, JsonRepresentation jsonRepresentation) {
54 List<ObjectNode> nodeList = new ArrayList<>();
55 for (R element : collection) {
56 ObjectNode node = createNode(element, jsonRepresentation);
62 public static <R> ObjectNode createNode(R bean, JsonRepresentation jsonRepresentation) {
63 ObjectMapper mapper = new ObjectMapper(new MappingJsonFactory());
64 return JacksonFilter.createNode(mapper, bean, jsonRepresentation.getAttributes());
67 private static <R> ObjectNode createNode(ObjectMapper mapper, R bean, Set<String> names) {
68 // split fieldNames in 2 categories :
69 // simpleFields for simple property names with no '.'
70 // nestedFields for nested property names with a '.'
71 Set<String> simpleFields = new LinkedHashSet<>();
72 MultiValueMap nestedFields = new LinkedMultiValueMap();
73 buildFields(names, simpleFields, nestedFields);
75 // create a simple node with only one level containing all simples
77 ObjectNode rootNode = JacksonFilter.createNodeWithSimpleFields(mapper, bean, simpleFields);
79 // create nested nodes with deeper levels
80 Set<Map.Entry<String, List<String>>> entrySet = nestedFields.entrySet();
81 // for each nested value, create recursively a node
82 for (Map.Entry<String, List<String>> entry : entrySet) {
83 String rootFieldName = entry.getKey();
84 // add in current node only if full value is not already present in
86 if (!simpleFields.contains(rootFieldName)) {
87 Object nestedBean = BeanUtils.getNestedProperty(bean, rootFieldName);
88 // add only non null fields
89 if (nestedBean == null) {
92 Set<String> nestedFieldNames = new LinkedHashSet<>(entry.getValue());
93 // current node is an array or a list
94 if ((nestedBean.getClass().isArray()) || (Collection.class.isAssignableFrom(nestedBean.getClass()))) {
95 handleListNode(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
97 // create recursively a node and add it in current root node
98 createNodeRecursively(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
105 private static void createNodeRecursively(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
106 Object nestedBean, Set<String> nestedFieldNames) {
107 ObjectNode nestedNode = JacksonFilter.createNode(mapper, nestedBean, nestedFieldNames);
108 if ((nestedNode != null) && (nestedNode.size() > 0)) {
109 rootNode.set(rootFieldName, nestedNode);
113 private static void buildFields(Set<String> names, Set<String> simpleFields, MultiValueMap nestedFields) {
114 for (String name : names) {
115 int index = name.indexOf('.');
116 boolean isNestedField = (index > 0) && (index < name.length());
118 String rootFieldName = name.substring(0, index);
119 String subFieldName = name.substring(index + 1);
120 nestedFields.add(rootFieldName, subFieldName);
122 simpleFields.add(name);
127 private static void handleListNode(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
128 Object nestedBean, Set<String> nestedFieldNames) {
129 Object[] array = null;
130 if ((nestedBean.getClass().isArray())) {
131 array = (Object[]) nestedBean;
133 Collection<?> collection = (Collection<?>) nestedBean;
134 array = collection.toArray();
136 if (array.length > 0) {
137 // create a node for each element in array
138 // and add created node in an arrayNode
139 Collection<JsonNode> nodes = new LinkedList<>();
140 for (Object object : array) {
141 ObjectNode nestedNode = JacksonFilter.createNode(mapper, object, nestedFieldNames);
142 if ((nestedNode != null) && (nestedNode.size() > 0)) {
143 nodes.add(nestedNode);
146 ArrayNode arrayNode = mapper.createArrayNode();
147 arrayNode.addAll(nodes);
148 if (arrayNode.size() > 0) {
149 rootNode.set(rootFieldName, arrayNode);
154 private static <R> ObjectNode createNodeWithSimpleFields(ObjectMapper mapper, R bean, Set<String> names) {
155 ObjectNode node = mapper.createObjectNode();
156 for (String name : names) {
157 // Prevent getting value of some fields
158 if (SKIPPED_FIELDS.contains(name)) {
162 JacksonFilter.nodePut(node, name, BeanUtils.getNestedProperty(bean, name));
167 private static void nodePut(ObjectNode node, String name, Object value) {
168 if (value instanceof Boolean) {
169 node.put(name, (Boolean) value);
170 } else if (value instanceof Integer) {
171 node.put(name, (Integer) value);
172 } else if (value instanceof Long) {
173 node.put(name, (Long) value);
174 } else if (value instanceof Float) {
175 node.put(name, (Float) value);
176 } else if (value instanceof Double) {
177 node.put(name, (Double) value);
178 } else if (value instanceof BigDecimal) {
179 node.put(name, (BigDecimal) value);
180 } else if (value instanceof String) {
181 node.put(name, (String) value);
183 node.putPOJO(name, value);