/*
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
*/
|
package com.megatim.dynamicjsonparser.extender;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
import com.megatim.dynamicjsonparser.pojo.CustomError;
|
import com.megatim.dynamicjsonparser.pojo.JsonField;
|
import com.megatim.dynamicjsonparser.pojo.JsonParsedData;
|
import com.megatim.dynamicjsonparser.pojo.Node;
|
import com.megatim.dynamicjsonparser.pojo.Indexe;
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.HashSet;
|
import java.util.Iterator;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Optional;
|
import java.util.Set;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
import org.apache.commons.validator.GenericValidator;
|
import org.burningwave.core.Virtual;
|
import org.burningwave.core.classes.Constructors;
|
|
/**
|
*
|
* @author ASUS
|
*/
|
public class JsonDataProcessor {
|
|
private final List<Node> nodes;
|
private final Class classOfEntity;
|
private final List<JsonField> jsonFields;
|
private final String rootClass;
|
|
private final JsonParsedData parsedData = new JsonParsedData();
|
|
public JsonDataProcessor(List<Node> nodes, Class classOfEntity, List<JsonField> jsonFields, String rootClass) {
|
this.nodes = nodes;
|
this.classOfEntity = classOfEntity;
|
this.jsonFields = jsonFields;
|
this.rootClass = rootClass;
|
}
|
|
public JsonParsedData iterateThroughNodes() {
|
for (Node node : nodes) {
|
|
Virtual virtualObject = traverseNode(node.getNode(), classOfEntity, jsonFields, Arrays.asList(new Indexe(node.getIndex())),
|
rootClass);
|
|
//Ajout de l'objet extrait dans la liste
|
parsedData.getVirtuals().add(virtualObject);
|
}
|
return parsedData;
|
}
|
|
private JsonField retrieveField(List<JsonField> jsonFields, String fieldName) {
|
Optional<JsonField> optJsonField = jsonFields.stream().filter(j -> j.getName().equalsIgnoreCase(fieldName)).findFirst();
|
if (optJsonField.isPresent()) {
|
return optJsonField.get();
|
} else {
|
return null;
|
}
|
}
|
|
/**
|
* Méthode permettant de parcourir recursivement les noeuds du fichier json
|
*
|
* @param node : noeud à parcourir
|
* @param classOfEntity : classe Java du noeud à parcourir
|
* @param map : map contenant tous champs de la classe Java à utiliser lors
|
* de l'extraction
|
* @param indexes : tableau contenant la hiérarchie des index, cad les index
|
* permettant de déterminer la posotion précise du noeud dans le fichier
|
* @return
|
*/
|
private Virtual traverseNode(final JsonNode node, final Class classOfEntity, final List<JsonField> jsonFields, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
if (node != null && classOfEntity != null && jsonFields != null && !jsonFields.isEmpty()) {
|
Iterator<Map.Entry<String, JsonNode>> nodeFields = node.fields();
|
Virtual virtualObject = new Constructors().newInstanceOf(classOfEntity);
|
Set<String> foundFields = new HashSet<>();//contient les champs rencontrés dans chaque noeud json
|
|
Integer index = indexes.get(0).getPosition();
|
|
while (nodeFields.hasNext()) {
|
|
Map.Entry<String, JsonNode> entry = nodeFields.next();
|
final JsonField dynamicField = retrieveField(jsonFields, entry.getKey());
|
|
//Si c'est un attribut de l'objet en cours de traitement
|
if (dynamicField != null) {
|
foundFields.add(entry.getKey());
|
|
if (entry.getValue().toString().equals("null")) {//si la valeur du noeud est à null
|
if (dynamicField.isRequired()) {
|
parsedData.getErrors().add(requiredErrorMessage(entry.getKey(), fullQualifiedNameOfField, indexes));
|
}
|
} else {
|
//Si la donnée que contient le noeud est un tableau
|
if (entry.getValue().isArray() && entry.getValue().size() > 0) {
|
|
JsonNode firstElement = entry.getValue().get(0);
|
|
//Si c'est un tableau d'objets
|
if (firstElement.isObject()) { //si c'est un tableau d'objets
|
traverseArrayOfObjectNodes(virtualObject, entry, dynamicField, indexes, fullQualifiedNameOfField);
|
} else {
|
traverseArrayOfTextualNodes(virtualObject, entry, dynamicField, indexes, fullQualifiedNameOfField);
|
}
|
} else if (entry.getValue().isObject()) {
|
traverseSingleObjectNode(virtualObject, entry, dynamicField, indexes, fullQualifiedNameOfField);
|
} else {
|
traverseSingleTextualNode(virtualObject, entry, dynamicField, indexes, fullQualifiedNameOfField);
|
}
|
}
|
} else {
|
CustomError customError = constructErrorMessage(indexes);
|
customError.getMessage().append("Attribut ").append("\"").append(fullQualifiedNameOfField).append(".").append(entry.getKey()).append("\"")
|
.append(" inexistant dans la définition de l'entité ").append("\"")
|
.append(jsonFields.get(0).getClassName())
|
.append("\"");
|
parsedData.getErrors().add(customError);
|
}
|
|
}
|
//Vérifier si des champs obligatoirs sont absents
|
checkIfRequiredFieldIsAbsent(foundFields, jsonFields, indexes, fullQualifiedNameOfField);
|
index++;
|
|
return virtualObject;
|
} else {
|
return null;
|
}
|
}
|
|
private void checkIfRequiredFieldIsAbsent(Set<String> foundFields, final List<JsonField> jsonFields, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
jsonFields.forEach(j -> {
|
if (j.isRequired() && !foundFields.stream().filter(f->f.equalsIgnoreCase(j.getName())).findFirst().isPresent()) {
|
parsedData.getErrors().add(requiredErrorMessage(j.getName(), fullQualifiedNameOfField, indexes));
|
}
|
});
|
}
|
|
private CustomError requiredErrorMessage(String key, String fullQualifiedNameOfField, List<Indexe> indexes) {
|
CustomError customError = constructErrorMessage(indexes);
|
customError.getMessage().append("La valeur de l'attribut ").append("\"").append(fullQualifiedNameOfField).append(".").append(key).append("\"")
|
.append(" ne peut être nulle ");
|
|
return customError;
|
}
|
|
private void traverseArrayOfTextualNodes(Virtual virtualObject, Map.Entry<String, JsonNode> entry, JsonField dynamicField, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
|
if (entry.getValue().toString().equals("null") || entry.getValue().size() == 0) {
|
if (dynamicField.isRequired()) {
|
parsedData.getErrors().add(requiredErrorMessage(entry.getKey(), fullQualifiedNameOfField, indexes));
|
}
|
return;
|
}
|
Class classOfField = dynamicField.getClazz();
|
CustomError customError = constructErrorMessage(indexes);
|
customError.getMessage().append("\"").append(fullQualifiedNameOfField).append(".").append(entry.getKey()).append("\"").append(" {");
|
|
boolean isTextFormatted = true;
|
List<Object> values = new ArrayList<>();
|
|
//On valide chaque élément du tableau
|
for (int i = 0; i < entry.getValue().size(); i++) {
|
Object finalObject = validateValue(entry.getValue().get(i).asText(), dynamicField);
|
|
//Si l'objet retourné après validation est nul, alors la validation a échoué
|
if (finalObject == null) {
|
customError.getMessage().append(" Elément N°").append(i + 1).append(" est mal formaté").append(", ");//On renseigne la position de l'élément qui a échoué
|
isTextFormatted = false;
|
|
} else if (finalObject.toString().length() > dynamicField.getLengthh()) {
|
customError.getMessage().append(" Elément N°").append(i + 1).append(" La taille de la donnée est supérieure à la taille attendue").append(", ");//On renseigne la position de l'élément qui a échoué
|
isTextFormatted = false;
|
}
|
values.add(finalObject);// ajouter l'élément au tableau final
|
}
|
|
if (!isTextFormatted) {
|
customError.getMessage().replace(customError.getMessage().length() - 2, customError.getMessage().length(), " }");
|
parsedData.getErrors().add(customError);
|
}
|
|
List finalValues = convertToRealType(values, classOfField);
|
virtualObject.invoke(setterofField(dynamicField.getName()), finalValues);
|
}
|
|
private void traverseArrayOfObjectNodes(Virtual virtualObject, Map.Entry<String, JsonNode> entry, JsonField dynamicField, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
if (entry.getValue().toString().equals("null") || entry.getValue().size() == 0) {
|
if (dynamicField.isRequired()) {
|
parsedData.getErrors().add(requiredErrorMessage(entry.getKey(), fullQualifiedNameOfField, indexes));
|
}
|
return;
|
}
|
List<Virtual> virtuals = new ArrayList<>();
|
List<Indexe> subIndexes = new ArrayList<>();
|
subIndexes.addAll(indexes);
|
|
subIndexes.add(new Indexe(1, fullQualifiedNameOfField + "." + entry.getKey()));
|
|
for (int i = 0; i < entry.getValue().size(); i++) {
|
|
//Valider de façon récursive les objets du tableau
|
virtuals.add(traverseNode(entry.getValue().get(i), dynamicField.getClazz(), dynamicField.getDynamicFields(), subIndexes, fullQualifiedNameOfField + "." + entry.getKey()));
|
|
int subPosition = subIndexes.get(subIndexes.size() - 1).getPosition();
|
subIndexes.get(subIndexes.size() - 1).setPosition(subPosition + 1);
|
}
|
|
virtualObject.invoke(setterofField(dynamicField.getName()), virtuals);
|
}
|
|
private void traverseSingleTextualNode(Virtual virtualObject, Map.Entry<String, JsonNode> entry, JsonField dynamicField, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
if (entry.getValue().toString().equals("null") || entry.getValue().asText().isEmpty()) {
|
if (dynamicField.isRequired()) {
|
parsedData.getErrors().add(requiredErrorMessage(entry.getKey(), fullQualifiedNameOfField, indexes));
|
}
|
return;
|
}
|
Object finalValue = validateValue(entry.getValue().asText(), dynamicField);
|
|
if (finalValue == null) {
|
CustomError customError = constructErrorMessage(indexes);
|
customError.getMessage().append("\"").append(fullQualifiedNameOfField).append(".").append(entry.getKey()).append("\"").append(" est mal formaté");
|
parsedData.getErrors().add(customError);
|
|
} else if (finalValue.toString().length() > dynamicField.getLengthh()) {
|
CustomError customError = constructErrorMessage(indexes);
|
customError.getMessage().append("\"").append(fullQualifiedNameOfField).append(".").append(entry.getKey()).append("\"").append(" La taille de la donnée est supérieure à la taille attendue");
|
parsedData.getErrors().add(customError);
|
} else {
|
virtualObject.invoke(setterofField(dynamicField.getName()), finalValue);
|
}
|
}
|
|
private void traverseSingleObjectNode(Virtual virtualObject, Map.Entry<String, JsonNode> entry, JsonField dynamicField, List<Indexe> indexes, String fullQualifiedNameOfField) {
|
List<Indexe> subIndexes = new ArrayList<>();
|
subIndexes.addAll(indexes);
|
subIndexes.add(new Indexe(entry.getKey()));
|
|
if (entry.getValue().toString().equals("null")) {
|
if (dynamicField.isRequired()) {
|
parsedData.getErrors().add(requiredErrorMessage(entry.getKey(), fullQualifiedNameOfField, indexes));
|
}
|
return;
|
}
|
Virtual virtual = traverseNode(entry.getValue(), dynamicField.getClazz(), dynamicField.getDynamicFields(), subIndexes, fullQualifiedNameOfField + "." + entry.getKey());
|
|
virtualObject.invoke(setterofField(dynamicField.getName()), virtual);
|
}
|
|
private boolean validateDate(String value, String formatDate, String separateurDate) {
|
boolean result = false;
|
|
StringBuilder dateToValidate = new StringBuilder(0);
|
|
if (separateurDate != null && !separateurDate.isEmpty()) {
|
|
String[] dateArray = value.split(separateurDate);
|
|
for (String d : dateArray) {
|
dateToValidate.append(d);
|
}
|
} else {
|
dateToValidate = new StringBuilder(value);
|
}
|
|
if (formatDate != null && !formatDate.isEmpty()) {
|
result = GenericValidator.isDate(dateToValidate.toString(), formatDate, false);
|
}
|
return result;
|
}
|
|
/**
|
* Méthode qui validate une donnée
|
*
|
* @param value
|
* @param classOfField
|
* @return
|
*/
|
private Object validateValue(String value, JsonField dynamicField) {
|
Object finalValue = null;
|
Class classOfField = dynamicField.getClazz();
|
|
try {
|
if (classOfField.isAssignableFrom(LocalDate.class)) {
|
|
boolean isFormatted = validateDate(value, dynamicField.getFormatDate(), dynamicField.getSeparateurDate());
|
|
if (isFormatted) {
|
finalValue = value;
|
}
|
|
} else if (classOfField.isAssignableFrom(Long.class)) {
|
|
finalValue = Long.valueOf(value);
|
} else if (classOfField.isAssignableFrom(BigDecimal.class)) {
|
finalValue = new BigDecimal(value);
|
|
} else {
|
finalValue = value;
|
}
|
} catch (Exception ex) {
|
}
|
return finalValue;
|
}
|
|
private List<LocalDate> convertListOfDate(List<Object> genericValues) {
|
List<LocalDate> listeLocalDate = new ArrayList<>();
|
|
genericValues.forEach(g -> {
|
|
LocalDate localDate = null;
|
|
if (g != null) {
|
localDate = (LocalDate) g;
|
}
|
|
listeLocalDate.add(localDate);
|
});
|
return listeLocalDate;
|
}
|
|
private List<Long> convertListOfLong(List<Object> genericValues) {
|
List<Long> listeLong = new ArrayList<>();
|
|
genericValues.forEach(g -> {
|
|
Long longValue = null;
|
|
if (g != null) {
|
longValue = (Long) g;
|
}
|
listeLong.add(longValue);
|
});
|
|
return listeLong;
|
}
|
|
private List<BigDecimal> convertListOfBigDecimal(List<Object> genericValues) {
|
List<BigDecimal> listeBigDecimal = new ArrayList<>();
|
|
genericValues.forEach(g -> {
|
|
BigDecimal bigDecimalValue = null;
|
|
if (g != null) {
|
bigDecimalValue = (BigDecimal) g;
|
}
|
|
listeBigDecimal.add(bigDecimalValue);
|
});
|
|
return listeBigDecimal;
|
}
|
|
private List<String> convertListOfString(List<Object> genericValues) {
|
List<String> listeString = new ArrayList<>();
|
|
genericValues.forEach(g -> {
|
|
String str = null;
|
|
if (g != null) {
|
str = (String) g;
|
}
|
|
listeString.add(str);
|
});
|
return listeString;
|
}
|
|
/**
|
* Méthode qui converti une liste d'objets en une liste d'un type précis
|
*
|
* @param genericValues
|
* @param classOfField
|
* @return
|
*/
|
private List convertToRealType(List<Object> genericValues, Class classOfField) {
|
|
if (classOfField.isAssignableFrom(LocalDate.class)) {
|
return convertListOfDate(genericValues);
|
|
} else if (classOfField.isAssignableFrom(Long.class)) {
|
return convertListOfLong(genericValues);
|
|
} else if (classOfField.isAssignableFrom(BigDecimal.class)) {
|
return convertListOfBigDecimal(genericValues);
|
|
} else {
|
return convertListOfString(genericValues);
|
}
|
}
|
|
private CustomError constructErrorMessage(List<Indexe> indexes) {
|
StringBuilder error = new StringBuilder();
|
CustomError customError = new CustomError();
|
customError.setEltNumber(indexes.get(0).getPosition());
|
|
indexes.forEach(indexe -> {
|
|
if (indexe.getFullQualifiedNameOfField() != null && !indexe.getFullQualifiedNameOfField().isEmpty() && indexe.getPosition() != 0) {
|
error.append("\"").append(indexe.getFullQualifiedNameOfField()).append("\"").append(" : ").append("Elément N° ").append(indexe.getPosition()).append(" : ");
|
|
} else if (indexe.getFullQualifiedNameOfField() != null && !indexe.getFullQualifiedNameOfField().isEmpty()) {
|
error.append("\"").append(indexe.getFullQualifiedNameOfField()).append("\"").append(" : ");
|
|
} else if (indexe.getPosition() != 0) {
|
error.append("Elément N° ").append(indexe.getPosition()).append(" : ");
|
}
|
});
|
|
customError.setMessage(error);
|
return customError;
|
}
|
|
private static String setterofField(String fieldName) {
|
|
String name = String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1);
|
|
return "set" + name;
|
}
|
}
|