Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sap.cds.impl.parser.StructDataParser Maven / Gradle / Ivy
/*******************************************************************
* © 2020 SAP SE or an SAP affiliate company. All rights reserved. *
*******************************************************************/
package com.sap.cds.impl.parser;
import static com.sap.cds.impl.parser.JsonParser.parseJson;
import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.sap.cds.ql.CdsDataException;
import com.sap.cds.reflect.CdsArrayedType;
import com.sap.cds.reflect.CdsAssociationType;
import com.sap.cds.reflect.CdsElementNotFoundException;
import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.reflect.CdsSimpleType;
import com.sap.cds.reflect.CdsStructuredType;
import com.sap.cds.reflect.CdsType;
import com.sap.cds.util.CdsTypeUtils;
public class StructDataParser {
private final CdsStructuredType rootType;
private StructDataParser(CdsStructuredType type) {
this.rootType = type;
}
public static StructDataParser create(CdsStructuredType type) {
return new StructDataParser(type);
}
public static List> parseArrayOf(CdsType itemType, String jsonArray) {
return parseArrayOf(itemType, jsonArray, Include.REJECTING);
}
public static List> parseArrayOf(CdsType itemType, String jsonArray, Include incl) {
if (itemType.isSimple()) {
return parseArrayOf(itemType.as(CdsSimpleType.class), jsonArray, incl);
}
if (itemType.isStructured()) {
return parseArrayOf(itemType.as(CdsStructuredType.class), jsonArray, incl);
}
throw new IllegalArgumentException("Cannot parser array of type " + itemType);
}
public static List parseArrayOf(CdsSimpleType itemType, String jsonArray) {
return parseArrayOf(itemType, jsonArray, Include.REJECTING);
}
@SuppressWarnings("unchecked")
public static List parseArrayOf(CdsSimpleType itemType, String jsonArray, Include incl) {
if (jsonArray != null) {
ArrayNode data = parseJson(jsonArray);
return (List) arrayToList(data, itemType, incl);
}
return null;
}
public static List> parseArrayOf(CdsStructuredType itemType, String jsonArray) {
return parseArrayOf(itemType, jsonArray, Include.REJECTING);
}
public static List> parseArrayOf(CdsStructuredType itemType, String jsonArray, Include incl) {
if (jsonArray != null) {
ArrayNode data = parseJson(jsonArray);
return arrayToList(data, itemType, incl);
}
return null;
}
public List> parseArray(String jsonArray) {
return parseArray(jsonArray, Include.REJECTING);
}
public List> parseArray(String jsonArray, Include incl) {
return parseArrayOf(rootType, jsonArray, incl);
}
public Map parseObject(String jsonObject) {
return parseObject(jsonObject, Include.REJECTING);
}
public Map parseObject(String jsonObject, Include incl) {
return objectToMap(parseJson(jsonObject), rootType, incl);
}
private static List> arrayToList(JsonNode array, CdsStructuredType type, Include incl) {
if (array != null) {
return stream(array.spliterator(), false).map(o -> objectToMap(o, type, incl)).collect(toList());
}
return Collections.emptyList();
}
private static List arrayToList(JsonNode array, CdsSimpleType type, Include incl) {
List data = new ArrayList<>();
if (array != null) {
array.forEach(entry -> data.add(convertValue(entry, type, incl)));
}
return data;
}
private static Map objectToMap(JsonNode object, CdsStructuredType type, Include incl) {
if (object == null) {
return null;
}
Map data = new HashMap<>(object.size());
object.fields().forEachRemaining(entry -> {
String element = entry.getKey();
try {
CdsType cdsType = (CdsType) type.findElement(element).map(e -> e.getType()).orElse(null);
switch (incl) {
case GENERIC:
data.put(element, convertValue(entry.getValue(), cdsType, incl));
break;
case REJECTING:
if (cdsType == null) {
throw new CdsElementNotFoundException(element, type);
}
data.put(element, convertValue(entry.getValue(), cdsType, incl));
break;
case IGNORING:
if (cdsType != null) {
data.put(element, convertValue(entry.getValue(), cdsType, incl));
}
}
} catch (CdsDataException e) {
throw new CdsDataException("Cannot parse value for " + type.getQualifiedName() + ":" + element, e);
}
});
return data;
}
private static Object convertValue(JsonNode val, CdsType type, Include incl) {
if (val.isNull()) {
return null;
}
if (type == null) {
try {
return JsonParser.object(val);
} catch (Exception e) {
throw new UnsupportedOperationException("Cannot parse value '" + val + "' for undefined type.");
}
}
if (type.isSimple() && val.isValueNode()) {
return CdsTypeUtils.parse(type.as(CdsSimpleType.class).getType(), val.asText());
}
if (type.isAssociation()) {
CdsAssociationType assoc = type.as(CdsAssociationType.class);
CdsEntity target = assoc.getTarget();
if (assoc.getCardinality().getTargetMax().equals("1")) {
return objectToMap(val, target, incl);
}
return arrayToList(val, target, incl);
}
if (type.isStructured() && val.isObject()) {
return objectToMap(val, type.as(CdsStructuredType.class), incl);
}
if (type.isArrayed() && val.isArray()) {
CdsType itemType = type.as(CdsArrayedType.class).getItemsType();
if (itemType.isStructured()) {
return arrayToList(val, itemType.as(CdsStructuredType.class), incl);
}
if (itemType.isSimple()) {
return arrayToList(val, itemType.as(CdsSimpleType.class), incl);
}
}
throw new UnsupportedOperationException("Cannot parse " + type + " value: " + val);
}
/**
* Defines how JSON data is handled that does not correspond to declared CDS properties.
*/
public static enum Include {
/**
* Tries to determine a default type of the undefined property and adds to the result data.
*/
GENERIC,
/**
* Rejects undefined properties by throwing a {@link CdsElementNotFoundException }.
*/
REJECTING,
/**
* The undefined properties are not included into the result data.
*/
IGNORING
}
}