All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.virtualan.mapson.Mapson Maven / Gradle / Ivy

Go to download

MAPson, CSVson library represents JSON as MAP with key as Json-Path and CSV based JSON representation. MAPson provides options to work json as MAP and Customized CSV.

The newest version!
/*
 *   Copyright (c) 2020.  Virtualan Software Contributors (https://virtualan.io)
 *
 *   Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 *   file except  in compliance with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software distributed under the
 *   License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 *   either express or implied. See the License for the specific language governing permissions
 *   and limitations under the License.
 */


package io.virtualan.mapson;

import io.virtualan.mapson.exception.BadInputDataException;
import io.virtualan.util.Helper;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * MAPson library represents JSON as MAP with key as Json-Path. MAPson provides options to work json
 * as MAP. It removes technical dependency between gherkin and Json. This would help lot more for
 * Product Owner/Business analysts(Non technical team members) can create a features without knowing
 * the details and simply using JSON hierarchy.
 */
@Slf4j
public class Mapson {

  private Mapson() {
  }


  /**
   * Build JSON string from Json-Path as key value pair. Usage refer read me file and test code for
   * examples
   *
   * @param jsonPathMap the json path as key value pair
   * @return the json string
   * @throws BadInputDataException the bad input data exception
   */
  public static String buildMAPsonAsJson(Map jsonPathMap)
      throws BadInputDataException {
    Map params = new LinkedHashMap<>();
    for (Map.Entry mapsonEntry : jsonPathMap.entrySet()) {
      String key = mapsonEntry.getKey();
      if (key.indexOf('.') != -1) {
        buildChildJson(params, key.split("\\."), mapsonEntry.getValue());
      } else if (key.contains("[") && key.contains("]")) {
        String originalKey = (key.indexOf(".") == -1) ? key.substring(0, key.indexOf("[")) : key;
        params.put(originalKey, buildObjectList(params, key, mapsonEntry.getValue()));
      } else {
        params.put(key, mapsonEntry.getValue());
      }
    }
    return buildJsonString(params).toString();
  }


  /**
   * Build JSON string from Json-Path as key value pair. Usage refer read me file and test code for
   * examples
   *
   * @param jsonPathMap the json path as key value pair
   * @return the json string
   * @throws BadInputDataException the bad input data exception
   */
  public static JSONObject buildMAPsonAsJsonObject(Map jsonPathMap)
      throws BadInputDataException {
    Map params = new LinkedHashMap<>();
    for (Map.Entry mapsonEntry : jsonPathMap.entrySet()) {
      String key = mapsonEntry.getKey();
      if (key.indexOf('.') != -1) {
        buildChildJson(params, key.split("\\."), mapsonEntry.getValue());
      } else if (key.contains("[") && key.contains("]")) {
        String originalKey = (key.indexOf(".") == -1) ? key.substring(0, key.indexOf("[")) : key;
        params.put(originalKey, buildObjectList(params, key, mapsonEntry.getValue()));
      } else {
        params.put(key, mapsonEntry.getValue());
      }
    }
    return buildJsonString(params);
  }


  /**
   * Build JSON string from Json-Path as key value pair. Context value could be replaced in the JSON
   * structure. Usage refer read me file and test code for examples
   *
   * @param jsonPathMap   the json path as key value pair
   * @param contextObject the context object
   * @return json as string
   * @throws BadInputDataException the bad input data exception
   */
  public static String buildMAPsonAsJson(Map jsonPathMap,
      Map contextObject) throws BadInputDataException {
    Map params = new LinkedHashMap<>();
    for (Map.Entry mapsonEntry : jsonPathMap.entrySet()) {
      String key = mapsonEntry.getKey();
      if (key.indexOf('.') != -1) {
        buildChildJson(params, key.split("\\."), Helper
            .getActualValue(mapsonEntry.getValue(), contextObject));
      } else if (key.contains("[") && key.contains("]")) {
        String elementAt = key.substring(0, key.indexOf('['));
        params.put(elementAt, buildObjectList(params, key,
            Helper.getActualValue(mapsonEntry.getValue(), contextObject)));
      } else {
        params.put(key, Helper.getActualValueForAll(mapsonEntry.getValue(), contextObject));
      }
    }

    JSONObject object =buildJsonString(params);
    if(object.optJSONArray("") != null){
      return ((JSONArray) object.get("")).toString(2);
    }
    return object.toString(2);
  }

  public static Object getJSON(String json) {
    try {
      return new JSONObject(json);
    } catch (JSONException err) {
      try {
        return new JSONArray(json);
      } catch (Exception e) {
        log.error("invalid JSON > " + json);
      }
    }
    return null;
  }

  /**
   * Build MAPson(Json-Path as key value pair) from json string. Usage refer read me file and test
   * code for examples
   *
   * @param json the json
   * @return the map
   */
  public static Map buildMAPsonFromJson(String json) {
    Object object = getJSON(json);
    Map mapsonMap = new LinkedHashMap<>();
    if (object != null) {
      if (object instanceof JSONArray) {
        getJSONPath(object, "", mapsonMap);
      } else {
        getJSONPath(object, null, mapsonMap);
      }
    }
    return mapsonMap;
  }

  private static List extractList(String key, Map jsonStructMap) {
    if (jsonStructMap.containsKey(key)) {
      return (List) jsonStructMap.get(key);
    } else {
      return new ArrayList<>();
    }
  }


  private static List buildObjectList(Map jsonStructMap,
      String elementAt, Object value) {
    String elementAtArray = elementAt.substring(0, elementAt.indexOf('['));
    int index = Integer.parseInt(elementAt.substring(elementAt.indexOf('[') + 1,
        elementAt.indexOf(']')));
    List elementList = extractList(elementAtArray, jsonStructMap);
    populateList(index, elementList, value);
    return elementList;
  }


  private static JSONObject buildJsonString(Map jsonStructMap,
      Map contextObject) {
    JSONObject jsonObject = new JSONObject();
    for (Map.Entry mapEntry : jsonStructMap.entrySet()) {
      if (mapEntry.getValue() instanceof Map) {
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(),
            buildJsonString((Map) mapEntry.getValue(), contextObject));
      } else if (mapEntry.getValue() instanceof List) {
        JSONArray array = new JSONArray();
        for (Object object : (List) mapEntry.getValue()) {
          if (object instanceof Map) {
            JSONObject obj = buildJsonString((Map) object);
            array.put(Helper.getActualValue(obj, contextObject));
          }
        }
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(), array);
      } else {
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(),
            Helper.getActualValue(mapEntry.getValue(), contextObject));
      }

    }
    return jsonObject;
  }
  public static JSONObject orderedJSONObject()  {
    JSONObject jsonObject = new JSONObject();
    try{
    Field map = jsonObject.getClass().getDeclaredField("map");
    map.setAccessible(true);//because the field is private final...
    map.set(jsonObject, new LinkedHashMap<>());
    map.setAccessible(false);//return flag
    }catch (Exception e){
      log.warn("Missing order of JSON Object");
    }
    return jsonObject;
  }

  private static JSONObject buildJsonString(Map jsonStructMap) {
    JSONObject jsonObject = orderedJSONObject();
    for (Map.Entry mapEntry : jsonStructMap.entrySet()) {
      if (mapEntry.getValue() instanceof Map) {
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(),
            buildJsonString((Map) mapEntry.getValue()));
      } else if (mapEntry.getValue() instanceof List) {
        JSONArray array = new JSONArray();
        for (Object object : (List) mapEntry.getValue()) {
          if (object instanceof Map) {
            JSONObject obj = buildJsonString((Map) object);
            array.put(obj);
          } else {
            DataTypeHelper.setObjectByType(array, object);
          }
        }
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(), array);
      } else {
        DataTypeHelper.setObject(jsonObject, mapEntry.getKey(), mapEntry.getValue());
      }

    }
    return jsonObject;
  }


  private static Map buildChildJson(Map jsonStructMap, String[] key,
      Object value) throws BadInputDataException {
    try {
      String elementAt = key[0];
      if (elementAt.contains("['") && elementAt.contains("']")) {
        String elementAtArray = elementAt.substring(0, elementAt.indexOf('['));
        String indexStr = elementAt.substring(elementAt.indexOf('[') + 1, elementAt.indexOf(']'));
        elementAt = elementAtArray + "." + elementAt
            .substring(elementAt.indexOf('[') + 2, elementAt.indexOf(']') - 1) + elementAt
            .substring(elementAt.indexOf("']") + 2);
      }
      if (elementAt.contains("[") && elementAt.contains("]")) {
        buildArrayOfObject(jsonStructMap, key, value, elementAt);
      } else {
        if (key.length == 1) {
          jsonStructMap.put(elementAt, value);
          return jsonStructMap;
        }
        buildMapAsJson(jsonStructMap, key, value, elementAt);
      }
    } catch (Exception e) {
      throw new BadInputDataException("Bad input exception :" + Arrays.toString(key));
    }
    return jsonStructMap;
  }

  private static void buildMapAsJson(Map jsonStructMap, String[] key, Object value,
      String elementAt) throws BadInputDataException {
    Map obj = extractDirectMap(jsonStructMap, elementAt);
    populateKeyPath(key, value, obj);
    jsonStructMap.put(elementAt, obj);
  }

  private static void populateKeyPath(String[] key, Object value, Map obj)
      throws BadInputDataException {
    String[] subKey = new String[key.length - 1];
    System.arraycopy(key, 1, subKey, 0, subKey.length);
    buildChildJson(obj, subKey, value);
  }

  private static Map extractDirectMap(Map jsonStructMap,
      String elementAt) {
    if (jsonStructMap.get(elementAt) != null) {
      return (Map) jsonStructMap.get(elementAt);
    } else {
      return new LinkedHashMap<>();
    }
  }

  private static void buildArrayOfObject(Map jsonStructMap, String[] key,
      Object value, String elementAt) throws BadInputDataException {
    String elementAtArray = elementAt.substring(0, elementAt.indexOf('['));
    String indexStr = elementAt.substring(elementAt.indexOf('[') + 1, elementAt.indexOf(']'));
    if (indexStr.length() == 0) {
      throw new BadInputDataException("Index missing for the json path :" + elementAt);
    }
    int index = Integer.parseInt(indexStr);
    List> elementList = extractElementList(jsonStructMap, elementAtArray);
    Map objListMap = extractMap(index, elementList);
    if(key.length ==1 &&  objListMap.isEmpty()){
      jsonStructMap.put(elementAt.substring(0, elementAt.indexOf("[")), buildObjectList(jsonStructMap, key[0], value));
    } else {
    populateKeyPath(key, value, objListMap);
    populateList(index, elementList, objListMap);
    jsonStructMap.put(elementAtArray, elementList);
    }

  }

  private static void populateList(int index, List> elementList,
      Map objListMap) {
    try {
      elementList.set(index, objListMap);
    } catch (IndexOutOfBoundsException e) {
      elementList.add(index, objListMap);
    }
  }

  private static void populateList(int index, List elementList, Object object) {
    try {
      elementList.set(index, object);
    } catch (IndexOutOfBoundsException e) {
      elementList.add(index, object);
    }
  }


  private static Map extractMap(int index, List> elementList) {
    if (elementList.size() > index) {
      return elementList.get(index);
    } else {
      return new LinkedHashMap<>();
    }
  }

  private static List> extractElementList(Map jsonStructMap,
      String elementAtArray) {
    List> elementList = new ArrayList<>();
    if (jsonStructMap.containsKey(elementAtArray)) {
      Object objectList = jsonStructMap.get(elementAtArray);
      if (objectList != null) {
        elementList = (List>) objectList;
      }
    }
    return elementList;
  }


  private static void getJSONPath(Object jsonObject, String key, Map mapsonMap) {
    if (jsonObject instanceof JSONObject) {
      getSubJson((JSONObject) jsonObject, key, mapsonMap);
    } else if (jsonObject instanceof JSONArray) {
      JSONArray jsonArray = ((JSONArray) jsonObject);
      int index = 0;
      getSubArrayPath(key, mapsonMap, jsonArray, index);
    }
  }

  private static void getSubJson(JSONObject jsonObject, String key, Map mapsonMap) {
    JSONObject jsonObject1 = jsonObject;
    Iterator keys = jsonObject1.keys();
    while (keys.hasNext()) {
      String keey = keys.next();
      String keeey = null;
      if (keey.contains(".")) {
        keeey = key == null ? keey
            : key + "." + keey.split("\\.")[0] + "['" + keey.split("\\.")[1] + "']";
      } else {
        keeey = key == null ? keey : key + "." + keey;
      }
      getSubPath(mapsonMap, jsonObject1, keey, keeey);
    }
  }

  private static void getSubArrayPath(String key, Map mapsonMap,
      JSONArray jsonArray, int index) {
   for(int i=0; i < jsonArray.length() ; i++){
    Object obj = jsonArray.get(i);
      if (obj instanceof JSONObject || obj instanceof JSONArray) {
        getJSONPath(obj, key + "[" + index++ + "]", mapsonMap);
      } else {
        String prefix = DataTypeHelper.getPrefixType(obj);
        mapsonMap.put(key + "[" + index++ + "]", prefix + obj);
      }
    }
  }

  private static void getSubPath(Map mapsonMap, JSONObject jsonObject1, String keey,
      String keeey) {
    if (jsonObject1.optJSONArray(keey) != null) {
      getJSONPath(jsonObject1.optJSONArray(keey), keeey, mapsonMap);
    } else if (jsonObject1.optJSONObject(keey) != null) {
      getJSONPath((JSONObject) jsonObject1.get(keey), keeey, mapsonMap);
    } else {
      String prefix = DataTypeHelper.getPrefixType(jsonObject1.get(keey));
      mapsonMap.put(keeey, prefix + jsonObject1.get(keey));
    }
  }

}