AbstractUtils.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.json;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openspcoop2.utils.SortedMap;
import org.openspcoop2.utils.UtilsException;
import org.slf4j.Logger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
/**
* AbstractUtils
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public abstract class AbstractUtils {
protected abstract void _initMapper();
protected abstract void _initWriter(boolean prettyPrint);
protected abstract ObjectMapper _getObjectMapper();
protected abstract ObjectWriter _getObjectWriter(boolean prettyPrint);
private boolean prettyPrint;
protected AbstractUtils(boolean prettyPrint) {
_initMapper();
this.prettyPrint = prettyPrint;
_initWriter(this.prettyPrint);
}
// GET AS
public JsonNode getAsNode(String jsonString) throws UtilsException {
try {
return _getObjectMapper().readTree(jsonString);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public JsonNode getAsNode(byte[] jsonBytes) throws UtilsException {
try {
return _getObjectMapper().readTree(jsonBytes);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public JsonNode getAsNode(InputStream jsonStream) throws UtilsException {
try {
return _getObjectMapper().readTree(jsonStream);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public JsonNode getAsNode(Reader jsonReader) throws UtilsException {
try {
return _getObjectMapper().readTree(jsonReader);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public JsonNode getAsNode(Map<?,?> map) throws UtilsException {
try {
return _getObjectMapper().valueToTree(map);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// GET AS OBJECT
public <T> T getAsObject(String jsonString, Class<T> c) throws UtilsException {
try {
return _getObjectMapper().readValue(jsonString, c);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public <T> T getAsObject(byte[] jsonBytes, Class<T> c) throws UtilsException {
try {
return _getObjectMapper().readValue(jsonBytes, c);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public <T> T getAsObject(InputStream jsonStream, Class<T> c) throws UtilsException {
try {
return _getObjectMapper().readValue(jsonStream, c);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public <T> T getAsObject(Reader jsonReader, Class<T> c) throws UtilsException {
try {
return _getObjectMapper().readValue(jsonReader, c);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// NEW DOCUMENT
public ObjectNode newObjectNode() throws UtilsException {
try {
return _getObjectMapper().createObjectNode();
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public ArrayNode newArrayNode() throws UtilsException {
try {
return _getObjectMapper().createArrayNode();
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public DateFormat getDateFormat() throws UtilsException {
try {
return _getObjectMapper().getDateFormat();
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// TO BYTE ARRAY
public byte[] toByteArray(JsonNode doc) throws UtilsException {
try {
return _getObjectWriter(this.prettyPrint).writeValueAsBytes(doc);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public byte[] toByteArray(Map<String, Object> doc) throws UtilsException {
try {
return _getObjectWriter(this.prettyPrint).writeValueAsBytes(doc);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// TO STRING
public String toString(JsonNode doc) throws UtilsException {
try {
return _getObjectWriter(this.prettyPrint).writeValueAsString(doc);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public String toString(Map<String, Object> doc) throws UtilsException {
try {
return _getObjectWriter(this.prettyPrint).writeValueAsString(doc);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// WRITE TO
public void writeTo(JsonNode doc, OutputStream os) throws UtilsException {
try {
_getObjectWriter(this.prettyPrint).writeValue(os, doc);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public void writeTo(Object object, OutputStream os) throws UtilsException {
try {
_getObjectWriter(this.prettyPrint).writeValue(os, object);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
// IS
protected boolean isValid(byte[]jsonBytes){
try {
getAsNode(jsonBytes);
return true;
} catch(Throwable e) {
return false;
}
}
protected boolean isValid(String jsonString){
try {
getAsNode(jsonString);
return true;
} catch(Throwable e) {
return false;
}
}
// UTILITIES
public Map<String, Serializable> convertToSimpleMap(JsonNode node){
return this.convertToSimpleMap(node, true, false, true, false, ".");
}
public Map<String, Serializable> convertToSimpleMap(JsonNode node, String separator){
return this.convertToSimpleMap(node, true, false, true, false, separator);
}
public Map<String, Serializable> convertToSimpleMap(JsonNode node,
boolean analyzeArrayNode, boolean analyzeAsStringArrayNode,
boolean analyzeObjectNode, boolean analyzeAsStringObjectNode,
String separator){
Map<String, Serializable> map = new HashMap<>();
_convertToSimpleMap(null, node, null, map,
analyzeArrayNode, analyzeAsStringArrayNode,
analyzeObjectNode, analyzeAsStringObjectNode,
separator);
return map;
}
private void _convertToSimpleMap(String name, JsonNode node, String prefix, Map<String, Serializable> map,
boolean analyzeArrayNode, boolean analyzeAsStringArrayNode,
boolean analyzeObjectNode, boolean analyzeAsStringObjectNode,
String separator){
String newPrefix = "";
if(prefix!=null) {
newPrefix = prefix+separator;
}
if(node instanceof ObjectNode) {
Iterator<String> iterator = node.fieldNames();
while(iterator.hasNext()) {
String field = iterator.next();
JsonNode child = node.get(field);
if(child instanceof ArrayNode) {
if(analyzeArrayNode) {
ArrayNode array = (ArrayNode) child;
if(array.size()>0) {
ArrayList<String> lString = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
if(arrayChildNode instanceof ArrayNode || arrayChildNode instanceof ObjectNode) {
String prefixRecursive = newPrefix+normalizeKey(field)+"["+i+"]";
_convertToSimpleMap(field, arrayChildNode, prefixRecursive, map,
analyzeArrayNode, analyzeAsStringArrayNode,
analyzeObjectNode, analyzeAsStringObjectNode,
separator);
}
else {
String text = arrayChildNode.asText();
if(text != null && !text.isEmpty())
lString.add(text);
}
}
if(!lString.isEmpty()) {
map.put(newPrefix+field, lString);
}
}
}
else if(analyzeAsStringArrayNode){
String text = child.asText();
if(text != null && !text.isEmpty())
map.put(newPrefix+field, text);
}
}
else if(child instanceof ObjectNode) {
if(analyzeObjectNode) {
ObjectNode object = (ObjectNode) child;
String prefixRecursive = newPrefix+normalizeKey(field);
_convertToSimpleMap(field, object, prefixRecursive, map,
analyzeArrayNode, analyzeAsStringArrayNode,
analyzeObjectNode, analyzeAsStringObjectNode,
separator);
}
else if(analyzeAsStringObjectNode){
String text = child.asText();
if(text != null && !text.isEmpty())
map.put(newPrefix+field, text);
}
}
else {
String text = child.asText();
if(text != null && !text.isEmpty())
map.put(newPrefix+field, text);
}
}
}
else if(node instanceof ArrayNode) {
ArrayNode array = (ArrayNode) node;
if(array.size()>0) {
ArrayList<String> lString = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
if(arrayChildNode instanceof ArrayNode || arrayChildNode instanceof ObjectNode) {
String prefixRecursive = newPrefix+normalizeKey(name)+"["+i+"]";
_convertToSimpleMap(name, arrayChildNode, prefixRecursive, map,
analyzeArrayNode, analyzeAsStringArrayNode,
analyzeObjectNode, analyzeAsStringObjectNode,
separator);
}
else {
String text = arrayChildNode.asText();
if(text != null && !text.isEmpty())
lString.add(text);
}
}
if(!lString.isEmpty()) {
map.put(name, lString);
}
}
}
else {
String text = node.asText();
if(text != null && !text.isEmpty()) {
map.put(name, text);
}
}
}
private static String normalizeKey(String keyParam) {
String key = keyParam.trim();
while(key.contains(" ")) {
key = key.replace(" ", "_");
}
return key;
}
// CONVERT TO MAP
protected Map<String, Serializable> convertToMapEngine(Logger log, String source, String raw, List<String> claimsToConvert) {
JsonNode jsonResponse = null;
try {
jsonResponse = this.getAsNode(raw);
}catch(Exception t) {
// ignore
}
return convertToMapEngine(log, source, jsonResponse, claimsToConvert);
}
protected Map<String, Serializable> convertToMapEngine(Logger log, String source, byte[]raw, List<String> claimsToConvert) {
JsonNode jsonResponse = null;
try {
jsonResponse = this.getAsNode(raw);
}catch(Exception t) {
// ignore
}
return convertToMapEngine(log, source, jsonResponse, claimsToConvert);
}
private Map<String, Serializable> convertToMapEngine(Logger log, String source, JsonNode jsonResponse, List<String> claimsToConvert) {
Map<String, Serializable> returnMap = new HashMap<>();
try {
if(jsonResponse instanceof ObjectNode) {
Iterator<String> iterator = jsonResponse.fieldNames();
while(iterator.hasNext()) {
String field = iterator.next();
if(claimsToConvert==null || claimsToConvert.contains(field)) {
try {
JsonNode selectedClaim = jsonResponse.get(field);
if(selectedClaim instanceof ValueNode) {
returnMap.put(field, selectedClaim.asText());
}
else if(selectedClaim instanceof ArrayNode) {
ArrayNode array = (ArrayNode) selectedClaim;
if(array.size()>0) {
JsonNode arrayFirstChildNode = array.get(0);
if(arrayFirstChildNode instanceof ValueNode) {
ArrayList<Serializable> l = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
Map<String, Serializable> readClaims = this.convertToSimpleMap(arrayChildNode);
if(readClaims!=null && readClaims.size()>0) {
if(readClaims.size()==1) {
for (String claim : readClaims.keySet()) {
Serializable value = readClaims.get(claim);
l.add(value);
}
}
else {
for (String claim : readClaims.keySet()) {
Serializable value = readClaims.get(claim);
addAttributeEngine(returnMap, claim==null ? field : claim, value);
}
}
}
}
if(!l.isEmpty()) {
addAttributeEngine(returnMap, field, l);
}
}
else {
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
Map<String, Serializable> readClaims = this.convertToSimpleMap(arrayChildNode);
if(readClaims!=null && readClaims.size()>0) {
for (String claim : readClaims.keySet()) {
Serializable value = readClaims.get(claim);
addAttributeEngine(returnMap, claim, value);
}
}
}
}
}
}
else {
Map<String, Serializable> readClaims = this.convertToSimpleMap(selectedClaim);
if(readClaims!=null && readClaims.size()>0) {
for (String claim : readClaims.keySet()) {
Serializable value = readClaims.get(claim);
addAttributeEngine(returnMap, claim, value);
}
}
}
}catch(Throwable e) {
log.error("Convert claim '"+field+"' to map failed ("+source+"): "+e.getMessage(),e);
}
}
}
}
}catch(Throwable e) {
// ignore
}
return returnMap;
}
private void addAttributeEngine(Map<String, Serializable> attributes, String claim, Serializable value) {
if(attributes.containsKey(claim)) {
for (int j = 1; j < 100; j++) {
String newKeyClaim = "_"+claim+"_"+j;
if(!attributes.containsKey(newKeyClaim)) {
attributes.put(newKeyClaim, attributes.get(claim));
break;
}
}
}
attributes.put(claim,value); // sovrascrive claim gia' esistente (e' stato salvato con un nome speciale)
}
// INSERT VALUE
public static final String CAST_PREFIX = "cast(";
public static final String CAST_SUFFIX_AS_INT = " as int)";
public static final String CAST_SUFFIX_AS_LONG = " as long)";
public static final String CAST_SUFFIX_AS_FLOAT = " as float)";
public static final String CAST_SUFFIX_AS_DOUBLE = " as double)";
public static final String CAST_SUFFIX_AS_BOOLEAN = " as boolean)";
private static final String CAST_ARRAY_OPTIONAL_EMPTY_RESULT = "cast( as string array)";
public static final String CAST_PREFIX_ARRAY = "cast([";
public static final String CAST_SUFFIX_AS_STRING_ARRAY = "] as string array)";
public void putValue(ObjectNode objectNode, String key, String value) throws UtilsException {
if(value!=null) {
String checkValue = value.trim();
if(CAST_ARRAY_OPTIONAL_EMPTY_RESULT.equals(checkValue)) {
// nop
}
else if(checkValue.startsWith(CAST_PREFIX_ARRAY) && checkValue.endsWith(CAST_SUFFIX_AS_STRING_ARRAY)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX_ARRAY.length(), (value.length()-CAST_SUFFIX_AS_STRING_ARRAY.length()));
String [] tmp = raw.split(",");
StringBuilder sb = new StringBuilder();
if(tmp!=null && tmp.length>0) {
for (int i = 0; i < tmp.length; i++) {
String check = tmp[i];
if(check!=null) {
check = check.trim();
}
if(StringUtils.isNotEmpty(check)) {
if(sb.length()>0) {
sb.append(",");
}
sb.append("\"").append(check).append("\"");
}
}
}
if(sb.length()>0) {
String newValue = "["+sb.toString()+"]";
JsonNode node = this.getAsNode(newValue);
objectNode.set(key, node);
}
else {
throw new Exception("empty value after parsing");
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as string array failed: "+t.getMessage(),t);
}
}
else if(checkValue.startsWith("[") && checkValue.endsWith("]")) {
try {
JsonNode node = this.getAsNode(value);
objectNode.set(key, node);
}catch(Throwable t) {
boolean throwException = true;
// provo ad aggiungere le stringhe
String s = checkValue.substring(1, checkValue.length()-1);
if(s!=null && StringUtils.isNotEmpty(s)) {
String [] tmp = s.split(",");
StringBuilder sb = new StringBuilder();
if(tmp!=null && tmp.length>0) {
for (int i = 0; i < tmp.length; i++) {
String check = tmp[i];
if(check!=null) {
check = check.trim();
}
if(StringUtils.isNotEmpty(check)) {
if(sb.length()>0) {
sb.append(",");
}
sb.append("\"").append(check).append("\"");
}
}
}
if(sb.length()>0) {
try {
String newValue = "["+sb.toString()+"]";
JsonNode node = this.getAsNode(newValue);
objectNode.set(key, node);
throwException = false;
}catch(Throwable t2) {
// rilancio prima eccezione
}
}
}
if(throwException) {
throw new UtilsException("Process value '"+value+"' as array node failed: "+t.getMessage(),t);
}
}
}
else if(checkValue.startsWith("{") && checkValue.endsWith("}")) {
JsonNode node = this.getAsNode(value);
objectNode.set(key, node);
}
else {
String checkValueLowerCase = checkValue.toLowerCase();
if(checkValueLowerCase.startsWith(CAST_PREFIX) && checkValueLowerCase.endsWith(CAST_SUFFIX_AS_INT)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX.length(), (value.length()-CAST_SUFFIX_AS_INT.length()));
if(raw!=null) {
raw = raw.trim();
if(StringUtils.isNotEmpty(raw)) {
int v = Integer.valueOf(raw);
objectNode.put(key, v);
}
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as int failed: "+t.getMessage(),t);
}
}
else if(checkValueLowerCase.startsWith(CAST_PREFIX) && checkValueLowerCase.endsWith(CAST_SUFFIX_AS_LONG)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX.length(), (value.length()-CAST_SUFFIX_AS_LONG.length()));
if(raw!=null) {
raw = raw.trim();
if(StringUtils.isNotEmpty(raw)) {
long v = Long.valueOf(raw);
objectNode.put(key, v);
}
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as long failed: "+t.getMessage(),t);
}
}
else if(checkValueLowerCase.startsWith(CAST_PREFIX) && checkValueLowerCase.endsWith(CAST_SUFFIX_AS_FLOAT)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX.length(), (value.length()-CAST_SUFFIX_AS_FLOAT.length()));
if(raw!=null) {
raw = raw.trim();
if(StringUtils.isNotEmpty(raw)) {
float v = Float.valueOf(raw);
objectNode.put(key, v);
}
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as float failed: "+t.getMessage(),t);
}
}
else if(checkValueLowerCase.startsWith(CAST_PREFIX) && checkValueLowerCase.endsWith(CAST_SUFFIX_AS_DOUBLE)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX.length(), (value.length()-CAST_SUFFIX_AS_DOUBLE.length()));
if(raw!=null) {
raw = raw.trim();
if(StringUtils.isNotEmpty(raw)) {
double v = Double.valueOf(raw);
objectNode.put(key, v);
}
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as double failed: "+t.getMessage(),t);
}
}
else if(checkValueLowerCase.startsWith(CAST_PREFIX) && checkValueLowerCase.endsWith(CAST_SUFFIX_AS_BOOLEAN)) {
String raw = value.trim();
try {
raw = value.substring(CAST_PREFIX.length(), (value.length()-CAST_SUFFIX_AS_BOOLEAN.length()));
if(raw!=null) {
raw = raw.trim();
if(StringUtils.isNotEmpty(raw)) {
boolean v = Boolean.valueOf(raw);
objectNode.put(key, v);
}
}
}catch(Throwable t) {
throw new UtilsException("Cast value '"+raw+"' as boolean failed: "+t.getMessage(),t);
}
}
else {
objectNode.put(key, value);
}
}
}
}
// RENAME
public void renameFieldByPath(JsonNode oNode, Map<String, String> pathToNewName) throws UtilsException {
renameFieldByPath(oNode, pathToNewName, true);
}
public void renameFieldByPath(JsonNode oNode, Map<String, String> pathToNewName, boolean throwNotFound) throws UtilsException {
renameFieldByPath(oNode, pathToNewName, false, throwNotFound);
}
public void renameFieldByPath(JsonNode oNode, Map<String, String> pathToNewName, boolean forceReorder, boolean throwNotFound) throws UtilsException {
if(pathToNewName==null || pathToNewName.isEmpty()) {
throw new UtilsException("Conversion map undefined");
}
for (String path : pathToNewName.keySet()) {
String newName = pathToNewName.get(path);
renameFieldByPath(oNode, path, newName, forceReorder, throwNotFound);
}
}
public void renameFieldByPath(JsonNode oNode, SortedMap<String> pathToNewName) throws UtilsException {
renameFieldByPath(oNode, pathToNewName, true);
}
public void renameFieldByPath(JsonNode oNode, SortedMap<String> pathToNewName, boolean throwNotFound) throws UtilsException {
renameFieldByPath(oNode, pathToNewName, false, throwNotFound);
}
public void renameFieldByPath(JsonNode oNode, SortedMap<String> pathToNewName, boolean forceReorder, boolean throwNotFound) throws UtilsException {
if(pathToNewName==null || pathToNewName.isEmpty()) {
throw new UtilsException("Conversion map undefined");
}
for (String path : pathToNewName.keys()) {
String newName = pathToNewName.get(path);
renameFieldByPath(oNode, path, newName, forceReorder, throwNotFound);
}
}
public void renameFieldByPath(JsonNode oNode, String path, String newName) throws UtilsException {
renameFieldByPath(oNode, path, newName, true);
}
public void renameFieldByPath(JsonNode oNode, String path, String newName, boolean throwNotFound) throws UtilsException {
renameFieldByPath(oNode, path, newName, false, throwNotFound);
}
public void renameFieldByPath(JsonNode oNode, String path, String newName, boolean forceReorder, boolean throwNotFound) throws UtilsException {
boolean esito = true;
int i = 0;
while(esito == true && i < 1000000) { // per avere un limite
try {
_renameFieldByPath(oNode, path, newName, forceReorder, true); // lasciare true
esito = true;
if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName) || newName.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
break; // serve un solo giro
}
}catch(UtilsException e) {
if(i==0){
if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName)) {
if(! (e.getMessage()!=null && e.getMessage().contains(ALREADY_ARRAY_TYPE_ERROR)) ) {
if(throwNotFound) {
throw e;
}
}
}
else if(newName.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
if(throwNotFound || (e.getMessage()!=null && !e.getMessage().contains("not found")) ) {
throw e;
}
}
else {
if(throwNotFound) {
throw e;
}
}
}
if(i>0) {
// almeno 1 occorrenza gestita
return;
}
esito = false;
}
i++;
}
}
public void _renameFieldByPath(JsonNode oNode, String path, String newName, boolean forceReorder, boolean throwNotFound) throws UtilsException {
String [] pathFragment = path.split("\\.");
if(pathFragment==null || pathFragment.length<=0) {
throw new UtilsException("Path undefined");
}
if(newName==null) {
throw new UtilsException("New name undefined");
}
if(!oNode.isObject()) {
throw new UtilsException("Node isn't object");
}
_StructureNode s = new _StructureNode();
s.parentNode = oNode;
s.nodeForRename = oNode;
_renameFieldByPath(s,
path, pathFragment, 0,
newName, forceReorder, throwNotFound);
}
private void _renameFieldByPath(_StructureNode structure,
String path, String [] pathFragment, int position,
String newName, boolean forceReorder, boolean throwNotFound) throws UtilsException {
//System.out.println("PROCESS ["+structure.parent+"]");
boolean foglia = position==pathFragment.length-1;
String name = pathFragment[position];
JsonNode parentNode = structure.parentNode;
JsonNode nodeForRename = structure.nodeForRename;
/*String parent = structure.parent;
System.out.println("navigo ["+name+"] (padre:"+parent+")");
if(nodeForRename.get(name)==null) {
System.out.println("isObject:"+nodeForRename.isObject());
System.out.println("isArray:"+nodeForRename.isArray());
}*/
parentNode = nodeForRename;
nodeForRename = nodeForRename.get(name);
if(nodeForRename==null || nodeForRename instanceof com.fasterxml.jackson.databind.node.MissingNode) {
if(throwNotFound &&
!"".equals(path) // "" rappresenta il root element json
) {
throw new UtilsException("Element '"+name+"' not found (path '"+path+"')");
}
}
if(foglia) {
//System.out.println("padre:"+parent+")");
//System.out.println(" newName:"+newName+")");
//System.out.println(" nodeForRename:"+nodeForRename+")");
//System.out.println(" parentNode:"+parentNode+")");
if(forceReorder) {
List<String> nomi = new ArrayList<>();
Iterator<String> it = ((ObjectNode)parentNode).fieldNames();
if(it!=null) {
while (it.hasNext()) {
String fieldName = (String) it.next();
nomi.add(fieldName);
}
}
for (String fieldName : nomi) {
JsonNode n = ((ObjectNode)parentNode).get(fieldName);
if(fieldName.equals(name)) {
// caso in gestione
if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName)) {
if(!n.isArray()) {
//System.out.println("CONVERT TO ARRAY ["+path+"] ["+fieldName+"]");
((ObjectNode)parentNode).remove(fieldName);
ArrayNode arrayNode = ((ObjectNode)parentNode).arrayNode();
arrayNode.add(n);
((ObjectNode)parentNode).set(fieldName,arrayNode);
}
else {
//System.out.println("GIA TROVATO COME ARRAY ["+path+"] ["+fieldName+"]");
if(throwNotFound) {
throw new UtilsException("Element '"+name+"' "+ALREADY_ARRAY_TYPE_ERROR+" (path '"+path+"')");
}
}
}
else {
((ObjectNode)parentNode).remove(fieldName);
((ObjectNode)parentNode).set(newName,n);
}
}
else {
// elementi da preservarne l'ordine
((ObjectNode)parentNode).remove(fieldName);
((ObjectNode)parentNode).set(fieldName,n);
}
}
}
else {
if(newName.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
// non supporta forceReorder, per quello non e' presente prima
List<String> l = convertReorderFieldChildrenByPathKeyToList(newName);
//System.out.println("REORDER--- "+l);
JsonNode attuale = null;
if("".equals(path)) {
attuale = ((ObjectNode)parentNode);
}
else {
attuale = ((ObjectNode)parentNode).get(name);
}
if(attuale.isArray()) {
//throw new UtilsException("Cannot execute reorder in array object (path '"+path+"')");
ArrayNode array = (ArrayNode) nodeForRename;
if(array!=null && array.size()>0) {
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
if(arrayChildNode.isObject()) {
// aggiungo elementi in ordine
for (String nameReorder : l) {
JsonNode n = arrayChildNode.get(nameReorder);
if(n==null || n instanceof com.fasterxml.jackson.databind.node.MissingNode) {
//System.out.println("REORDERN NOT FOUND PARENT throwNotFound["+throwNotFound+"] ["+(attuale)+"]");
//throw new UtilsException("Element '"+nameReorder+"' for reorder not found (path '"+path+"')");
}
else {
//System.out.println("REORDER["+nameReorder+"]");
((ObjectNode)arrayChildNode).remove(nameReorder);
((ObjectNode)arrayChildNode).set(nameReorder, n);
}
}
}
else {
throw new UtilsException("Cannot execute reorder in simple object (path '"+path+"') (array position i="+i+")");
}
}
}
}
else if(attuale.isObject()) {
// aggiungo elementi in ordine
for (String nameReorder : l) {
JsonNode n = attuale.get(nameReorder);
if(n==null || n instanceof com.fasterxml.jackson.databind.node.MissingNode) {
//System.out.println("REORDERN NOT FOUND PARENT throwNotFound["+throwNotFound+"] ["+(attuale)+"]");
//throw new UtilsException("Element '"+nameReorder+"' for reorder not found (path '"+path+"')");
}
else {
//System.out.println("REORDER["+nameReorder+"]");
((ObjectNode)attuale).remove(nameReorder);
((ObjectNode)attuale).set(nameReorder, n);
}
}
}
else {
throw new UtilsException("Cannot execute reorder in simple object (path '"+path+"')");
}
}
else if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName)) {
if(nodeForRename!=null && !nodeForRename.isArray()) {
//System.out.println("CONVERT TO ARRAY ["+path+"] ["+name+"]");
((ObjectNode)parentNode).remove(name);
ArrayNode arrayNode = ((ObjectNode)parentNode).arrayNode();
arrayNode.add(nodeForRename);
((ObjectNode)parentNode).set(name,arrayNode);
}
else {
//System.out.println("GIA TROVATO COME ARRAY ["+path+"] ["+name+"]");
if(throwNotFound) {
throw new UtilsException("Element '"+name+"' "+ALREADY_ARRAY_TYPE_ERROR+" (path '"+path+"')");
}
}
}
else {
((ObjectNode)parentNode).remove(name);
((ObjectNode)parentNode).set(newName,nodeForRename);
}
}
}
else {
if(nodeForRename!=null && nodeForRename.isObject() && nodeForRename instanceof ObjectNode) {
_StructureNode s = new _StructureNode();
s.parentNode = parentNode;
s.nodeForRename = nodeForRename;
s.parent = name;
//System.out.println("CHIAMO PER OBJECT s.parent["+s.parent+"]");
try {
_renameFieldByPath(s,
path, pathFragment, position+1,
newName, forceReorder, throwNotFound);
}catch(UtilsException e) {
if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName)) {
if(! (e.getMessage()!=null && e.getMessage().contains(ALREADY_ARRAY_TYPE_ERROR)) ) {
throw e;
}
}
else if(newName.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
if(e.getMessage()!=null && !e.getMessage().contains("not found")) {
throw e;
}
}
else {
throw e;
}
}
}
else if(nodeForRename!=null && nodeForRename.isArray() && nodeForRename instanceof ArrayNode) {
ArrayNode array = (ArrayNode) nodeForRename;
if(array.size()>0) {
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
_StructureNode s = new _StructureNode();
s.parentNode = nodeForRename;
s.nodeForRename = arrayChildNode;
s.parent = name+"["+i+"]";
//System.out.println("CHIAMO PER ARRAY s.parent["+s.parent+"]");
try {
_renameFieldByPath(s,
path, pathFragment, position+1,
newName, forceReorder, throwNotFound);
}catch(UtilsException e) {
if(SPECIAL_KEY_CONVERT_TO_ARRAY.equals(newName)) {
if(! (e.getMessage()!=null && e.getMessage().contains(ALREADY_ARRAY_TYPE_ERROR)) ) {
throw e;
}
}
else if(newName.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
if(e.getMessage()!=null && !e.getMessage().contains("not found")) {
throw e;
}
}
else {
throw e;
}
}
}
}
}
else {
throw new UtilsException("Element '"+name+"' not found as object/array (path '"+path+"')");
}
}
}
public void renameFieldInCamelCase(JsonNode oNode, boolean firstLowerCase) throws UtilsException {
renameFieldInCamelCase(oNode, firstLowerCase, false);
}
public void renameFieldInCamelCase(JsonNode oNode, boolean firstLowerCase, boolean forceReorder) throws UtilsException {
SortedMap<String> mapForRename = new SortedMap<String>();
if(!oNode.isObject()) {
throw new UtilsException("Node isn't object");
}
renameFieldInCamelCase((ObjectNode)oNode, "", mapForRename, firstLowerCase, forceReorder);
if(!mapForRename.isEmpty()) {
/*for (String path : mapForRename.keys()) {
System.out.println("MAP ["+path+"] -> ["+mapForRename.get(path)+"]");
}*/
renameFieldByPath(oNode, mapForRename);
}
}
private static void renameFieldInCamelCase(ObjectNode oNode, String prefix, SortedMap<String> mapForRename,
boolean firstLowerCase, boolean forceReorder) throws UtilsException {
Iterator<String> it = oNode.fieldNames();
if(it!=null) {
while (it.hasNext()) {
String fieldName = (String) it.next();
JsonNode node = oNode.get(fieldName);
if(node!=null){
if(node.isObject() && node instanceof ObjectNode) {
if(StringUtils.isNotEmpty(prefix) && !prefix.endsWith(".")){
prefix = prefix + ".";
}
renameFieldInCamelCase((ObjectNode)node , prefix+fieldName, mapForRename, firstLowerCase, forceReorder);
}
else if(node.isArray() && node instanceof ArrayNode) {
ArrayNode array = (ArrayNode) node;
if(array.size()>0) {
for (int i = 0; i < array.size(); i++) {
JsonNode arrayChildNode = array.get(i);
if(arrayChildNode.isObject() && arrayChildNode instanceof ObjectNode) {
if(StringUtils.isNotEmpty(prefix) && !prefix.endsWith(".")){
prefix = prefix + ".";
}
renameFieldInCamelCase((ObjectNode)arrayChildNode , prefix+fieldName, mapForRename, firstLowerCase, forceReorder);
}
}
}
}
}
String camelCaseName = camelCase(fieldName, firstLowerCase);
if(!camelCaseName.equals(fieldName) || forceReorder) {
if(StringUtils.isNotEmpty(prefix) && !prefix.endsWith(".")){
prefix = prefix + ".";
}
String key = prefix+fieldName;
if(!mapForRename.containsKey(key)) {
mapForRename.add(key, camelCaseName);
}
}
}
}
}
public static String camelCase(String fieldName, boolean firstLowerCase) {
boolean firstCase = firstLowerCase ? Character.isUpperCase(fieldName.charAt(0)) : Character.isLowerCase(fieldName.charAt(0));
boolean charSpecial = fieldName.contains("-") || fieldName.contains("_");
if (firstCase || charSpecial) {
String newName = fieldName;
//System.out.println("ANALIZZO ["+newName+"]");
if(firstCase) {
if(firstLowerCase) {
newName = (fieldName.length()>1) ?
(((fieldName.charAt(0)+"").toLowerCase()) + fieldName.substring(1))
:
(fieldName.toLowerCase());
}
else {
newName = (fieldName.length()>1) ?
(((fieldName.charAt(0)+"").toUpperCase()) + fieldName.substring(1))
:
(fieldName.toUpperCase());
}
//System.out.println("DOPO UPPER ["+newName+"]");
}
if(charSpecial) {
int indexOf = newName.indexOf("_");
while(indexOf>=0){
if((indexOf+1)<newName.length()){
if((indexOf+2)<newName.length()){
newName = newName.substring(0, indexOf) + (newName.charAt(indexOf+1)+"").toUpperCase() + newName.substring(indexOf+2,newName.length());
}else{
newName = newName.substring(0, indexOf) + (newName.charAt(indexOf+1)+"").toUpperCase();
}
indexOf = newName.indexOf("_");
}else{
break;
}
}
indexOf = newName.indexOf("-");
while(indexOf>=0){
if((indexOf+1)<newName.length()){
if((indexOf+2)<newName.length()){
newName = newName.substring(0, indexOf) + (newName.charAt(indexOf+1)+"").toUpperCase() + newName.substring(indexOf+2,newName.length());
}else{
newName = newName.substring(0, indexOf) + (newName.charAt(indexOf+1)+"").toUpperCase();
}
indexOf = newName.indexOf("-");
}else{
break;
}
}
//System.out.println("DOPO CHAR ["+newName+"]");
}
return newName;
}
else {
return fieldName;
}
}
// CONVERT TYPE
private static final String SPECIAL_KEY_CONVERT_TO_ARRAY = "___CONVERT_TO_ARRAY__";
private static final String ALREADY_ARRAY_TYPE_ERROR = "already array type";
public void convertFieldToArrayByPath(JsonNode oNode, List<String> listPath) throws UtilsException {
SortedMap<String> pathToNewName = new SortedMap<String>();
if(listPath!=null) {
for (String path : listPath) {
pathToNewName.add(path, SPECIAL_KEY_CONVERT_TO_ARRAY);
}
}
renameFieldByPath(oNode, pathToNewName, true);
}
public void convertFieldToArrayByPath(JsonNode oNode, List<String> listPath, boolean throwNotFound) throws UtilsException {
SortedMap<String> pathToNewName = new SortedMap<String>();
if(listPath!=null) {
for (String path : listPath) {
pathToNewName.add(path, SPECIAL_KEY_CONVERT_TO_ARRAY);
}
}
renameFieldByPath(oNode, pathToNewName, throwNotFound);
}
public void convertFieldToArrayByPath(JsonNode oNode, List<String> listPath, boolean forceReorder, boolean throwNotFound) throws UtilsException {
SortedMap<String> pathToNewName = new SortedMap<String>();
if(listPath!=null) {
for (String path : listPath) {
pathToNewName.add(path, SPECIAL_KEY_CONVERT_TO_ARRAY);
}
}
renameFieldByPath(oNode, pathToNewName, forceReorder, throwNotFound);
}
public void convertFieldToArrayByPath(JsonNode oNode, String path) throws UtilsException {
renameFieldByPath(oNode, path, SPECIAL_KEY_CONVERT_TO_ARRAY, true);
}
public void convertFieldToArrayByPath(JsonNode oNode, String path, boolean throwNotFound) throws UtilsException {
renameFieldByPath(oNode, path, SPECIAL_KEY_CONVERT_TO_ARRAY, throwNotFound);
}
public void convertFieldToArrayByPath(JsonNode oNode, String path, boolean forceReorder, boolean throwNotFound) throws UtilsException {
renameFieldByPath(oNode, path, SPECIAL_KEY_CONVERT_TO_ARRAY, forceReorder, throwNotFound);
}
// ORDER ELEMENTS TYPE
private static final String SPECIAL_KEY_ORDER_ELEMENTS_PREFIX = "___REORDER__";
private static final String SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR = ",";
public void reorderFieldChildrenByPath(JsonNode oNode, String path, String ... child) throws UtilsException {
renameFieldByPath(oNode, path, SPECIAL_KEY_ORDER_ELEMENTS_PREFIX+toReorderFieldChildrenByPathSuffix(child), true);
}
public void reorderFieldChildrenByPath(JsonNode oNode, String path, boolean throwNotFound, String ... child) throws UtilsException {
String key = SPECIAL_KEY_ORDER_ELEMENTS_PREFIX+toReorderFieldChildrenByPathSuffix(child);
//System.out.println("KEY ["+key+"]");
renameFieldByPath(oNode, path, key, throwNotFound);
}
private String toReorderFieldChildrenByPathSuffix(String ... child) throws UtilsException {
if(child==null || child.length<=0) {
throw new UtilsException("Children undefined");
}
StringBuilder sb = new StringBuilder();
for (String c : child) {
if(sb.length()>0) {
sb.append(SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR);
}
if(c.contains(SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR)) {
throw new UtilsException("Invalid child name ["+c+"] (contains '"+SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR+"')");
}
sb.append(c);
}
return sb.toString();
}
private List<String> convertReorderFieldChildrenByPathKeyToList(String v) throws UtilsException{
String parsV = v;
if(parsV.startsWith(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX)) {
parsV = parsV.substring(SPECIAL_KEY_ORDER_ELEMENTS_PREFIX.length());
}
List<String> l = new ArrayList<>();
if(parsV.contains(SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR)) {
String [] tmp = parsV.split(SPECIAL_KEY_ORDER_ELEMENTS_SEPARATOR);
if(tmp!=null && tmp.length>0) {
for (String c : tmp) {
l.add(c);
}
}
}
else {
l.add(parsV);
}
if(l.isEmpty()) {
throw new UtilsException("Children not found");
}
return l;
}
}
class _StructureNode {
JsonNode parentNode;
JsonNode nodeForRename;
String parent;
}