geoportal-data-entry-app/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/FormDataObjectToJSON.java

218 lines
6.3 KiB
Java

package org.gcube.portlets.user.geoportaldataentry.server;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import org.gcube.application.geoportalcommon.shared.geoportal.config.GcubeProfileDV;
import org.gcube.portlets.user.geoportaldataentry.shared.GeoNaFormDataObject;
import org.gcube.portlets.widgets.mpformbuilder.shared.GenericDatasetBean;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class FormDataObjectToJSON.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Mar 10, 2022
*/
public class FormDataObjectToJSON {
private static final Logger LOG = LoggerFactory.getLogger(FormDataObjectToJSON.class);
/**
* Convert.
*
* @param listGeonaFormObjects the list geona form objects
* @return the JSON object
* @throws JSONException the JSON exception
*/
public JSONObject convert(List<GeoNaFormDataObject> listGeonaFormObjects) throws JSONException {
JSONObject theDocument = JSONObjecOrdered.instance();
for (GeoNaFormDataObject geoNaFormDataObject : listGeonaFormObjects) {
List<GenericDatasetBean> listGDB = geoNaFormDataObject.getListGDB();
GcubeProfileDV profile = geoNaFormDataObject.getGcubeProfileDV();
LOG.debug("The profile is: " + profile);
String jsonPathExp = String.format("%s%s", profile.getParentName(), profile.getSectionName());
LOG.debug("The json path to build: " + jsonPathExp);
// jsonPathExp = "$.chidl1.child2.child3";
String toJsonPathExp = jsonPathExp.replaceFirst("\\$", "");
String[] jsonPathDeep = toJsonPathExp.split("\\.");
List<JSONObject> listJSONObject = toListJonObject(listGDB, jsonPathDeep);
// adding as JSONObject to theDocument at first deep level (under the root or at section specified)
if (listJSONObject.size() == 1) {
theDocument = deepMerge(listJSONObject.get(0), theDocument);
//theDocument = theDocument.put(listJSONObject.get(0), jsonArray);
} else {
// adding as JSONArray to theDocument under the section specified
// to jsonPathDeep[1]
JSONArray jsonArray = new JSONArray();
for (JSONObject jsonObject : listJSONObject) {
// reading the i-mo JSONObject created in the list with the key as
// jsonPathDeep[1]
jsonArray.put(jsonObject.get(jsonPathDeep[1]));
}
theDocument.put(jsonPathDeep[1], jsonArray);
}
LOG.debug("Partial Root Document is: " + theDocument);
}
LOG.debug("Final JSON Document is: " + theDocument);
return theDocument;
}
/**
* Generic dataset bean to JSON.
*
* @param gdb the gdb
* @return the JSON object
* @throws JSONException the JSON exception
*/
private JSONObject genericDatasetBeanToJSON(GenericDatasetBean gdb) throws JSONException {
JSONObject sectJSONObject = JSONObjecOrdered.instance();
LinkedHashMap<String, List<String>> mapFields = gdb.getFormDataEntryFields();
LOG.debug("Map ordered: " + mapFields);
for (String key : mapFields.keySet()) {
List<String> listValues = mapFields.get(key);
if (listValues == null || listValues.isEmpty()) {
continue;
}
// key/value as string
if (listValues.size() == 1) {
sectJSONObject.put(key, listValues.get(0));
continue;
}
// value is a list
JSONArray array = new JSONArray();
for (String value : listValues) {
array.put(value);
}
sectJSONObject.put(key, array);
}
return sectJSONObject;
}
/**
* To list jon object.
*
* @param listGDB the list GDB
* @param jsonPathDeep the json path deep
* @return the list
* @throws JSONException the JSON exception
*/
private List<JSONObject> toListJonObject(List<GenericDatasetBean> listGDB, String[] jsonPathDeep)
throws JSONException {
List<JSONObject> listJSONObject = new ArrayList<JSONObject>();
for (GenericDatasetBean gdb : listGDB) {
JSONObject sectRootObject = JSONObjecOrdered.instance();
JSONObject jsonObject = genericDatasetBeanToJSON(gdb);
LOG.debug("Adding section : " + jsonObject);
LOG.trace("jsonPathDeep: " + Arrays.asList(jsonPathDeep) + " size: " + jsonPathDeep.length);
// Adding JSONObject to ROOT DOCUMENT POSITION (using PLACEHOLDER_ROOT_POINTER_JSON_DOC)
if (jsonPathDeep.length == 0) {
sectRootObject = deepMerge(jsonObject, sectRootObject);
} else {
// DEPTH >= 1
sectRootObject.put(jsonPathDeep[jsonPathDeep.length - 1], jsonObject);
JSONObject deepJSON = sectRootObject;
System.out.println("sectRootObject: " + sectRootObject.toString());
for (int i = jsonPathDeep.length - 2; i > 0; i--) {
JSONObject newOne = JSONObjecOrdered.instance();
newOne.put(jsonPathDeep[i], deepJSON);
deepJSON = newOne;
}
sectRootObject = deepJSON;
}
listJSONObject.add(sectRootObject);
}
LOG.info("For listGDB : " + listGDB);
LOG.info("returning : " + listJSONObject);
return listJSONObject;
}
/**
* Merge "source" into "target". If fields have equal name, merge them
* recursively.
*
* @param source the source
* @param target the target
* @return the merged object (target).
* @throws JSONException the JSON exception
*/
public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException {
for (String key : JSONObject.getNames(source)) {
Object value = source.get(key);
if (!target.has(key)) {
// new value for "key":
target.put(key, value);
} else {
// existing value for "key" - recursively deep merge:
if (value instanceof JSONObject) {
JSONObject valueJson = (JSONObject) value;
deepMerge(valueJson, target.getJSONObject(key));
} else {
target.put(key, value);
}
}
}
return target;
}
/**
* The Class JSONObjecOrdered.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Mar 10, 2022
*/
public static class JSONObjecOrdered {
/**
* Instance.
*
* @return the JSON object
*/
public static JSONObject instance() {
JSONObject jsonObject = new JSONObject();
try {
Field changeMap = jsonObject.getClass().getDeclaredField("map");
changeMap.setAccessible(true);
changeMap.set(jsonObject, new LinkedHashMap<>());
changeMap.setAccessible(false);
} catch (IllegalAccessException | NoSuchFieldException e) {
}
return jsonObject;
}
}
}