/* * 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 nodes; private final Class classOfEntity; private final List jsonFields; private final String rootClass; private final JsonParsedData parsedData = new JsonParsedData(); public JsonDataProcessor(List nodes, Class classOfEntity, List 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 jsonFields, String fieldName) { Optional 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 jsonFields, List indexes, String fullQualifiedNameOfField) { if (node != null && classOfEntity != null && jsonFields != null && !jsonFields.isEmpty()) { Iterator> nodeFields = node.fields(); Virtual virtualObject = new Constructors().newInstanceOf(classOfEntity); Set foundFields = new HashSet<>();//contient les champs rencontrés dans chaque noeud json Integer index = indexes.get(0).getPosition(); while (nodeFields.hasNext()) { Map.Entry 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 foundFields, final List jsonFields, List 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 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 entry, JsonField dynamicField, List 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 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 entry, JsonField dynamicField, List 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 virtuals = new ArrayList<>(); List 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 entry, JsonField dynamicField, List 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 entry, JsonField dynamicField, List indexes, String fullQualifiedNameOfField) { List 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 convertListOfDate(List genericValues) { List listeLocalDate = new ArrayList<>(); genericValues.forEach(g -> { LocalDate localDate = null; if (g != null) { localDate = (LocalDate) g; } listeLocalDate.add(localDate); }); return listeLocalDate; } private List convertListOfLong(List genericValues) { List listeLong = new ArrayList<>(); genericValues.forEach(g -> { Long longValue = null; if (g != null) { longValue = (Long) g; } listeLong.add(longValue); }); return listeLong; } private List convertListOfBigDecimal(List genericValues) { List listeBigDecimal = new ArrayList<>(); genericValues.forEach(g -> { BigDecimal bigDecimalValue = null; if (g != null) { bigDecimalValue = (BigDecimal) g; } listeBigDecimal.add(bigDecimalValue); }); return listeBigDecimal; } private List convertListOfString(List genericValues) { List 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 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 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; } }