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

com.sap.cds.impl.parser.StructDataParser Maven / Gradle / Ivy

There is a newer version: 3.6.1
Show newest version
/*******************************************************************
 * © 2020 SAP SE or an SAP affiliate company. All rights reserved. *
 *******************************************************************/
package com.sap.cds.impl.parser;

import static com.sap.cds.impl.parser.CqnParser.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.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) {
		if (itemType.isSimple()) {
			return parseArrayOf(itemType.as(CdsSimpleType.class), jsonArray);
		}
		if (itemType.isStructured()) {
			return parseArrayOf(itemType.as(CdsStructuredType.class), jsonArray);
		}
		throw new IllegalArgumentException("Cannot parser array of type " + itemType);
	}

	@SuppressWarnings("unchecked")
	public static  List parseArrayOf(CdsSimpleType itemType, String jsonArray) {
		if (jsonArray != null) {
			ArrayNode data = parseJson(jsonArray);

			return (List) arrayToList(data, itemType);
		}
		return null;
	}

	public static List> parseArrayOf(CdsStructuredType itemType, String jsonArray) {
		if (jsonArray != null) {
			ArrayNode data = parseJson(jsonArray);

			return arrayToList(data, itemType);
		}
		return null;
	}

	public List> parseArray(String jsonArray) {
		return parseArrayOf(rootType, jsonArray);
	}

	public Map parseObject(String jsonObject) {
		return objectToMap(parseJson(jsonObject), rootType);
	}

	private static List> arrayToList(JsonNode array, CdsStructuredType type) {
		if (array != null) {
			return stream(array.spliterator(), false).map(o -> objectToMap(o, type)).collect(toList());
		}
		return Collections.emptyList();
	}

	private static List arrayToList(JsonNode array, CdsSimpleType type) {
		List data = new ArrayList<>();
		if (array != null) {
			array.forEach(entry -> data.add(convertValue(entry, type)));
		}
		return data;
	}

	private static Map objectToMap(JsonNode object, CdsStructuredType type) {
		if (object == null) {
			return null;
		}
		Map data = new HashMap<>(object.size());
		object.fields().forEachRemaining(entry -> {
			String element = entry.getKey();
			try {
				Object value = convertValue(entry.getValue(), type.getElement(element).getType());
				data.put(element, value);
			} catch (CdsDataException e) {
				throw new CdsDataException("Cannot parse value for " + type.getQualifiedName() + ":" + element, e);
			}
		});
		return data;
	}

	private static Object convertValue(JsonNode val, CdsType type) {
		if (val.isNull()) {
			return null;
		}
		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);
			}
			return arrayToList(val, target);
		}
		if (type.isStructured() && val.isObject()) {
			return objectToMap(val, type.as(CdsStructuredType.class));
		}
		if (type.isArrayed() && val.isArray()) {
			CdsType itemType = type.as(CdsArrayedType.class).getItemsType();
			if (itemType.isStructured()) {
				return arrayToList(val, itemType.as(CdsStructuredType.class));
			}
			if (itemType.isSimple()) {
				return arrayToList(val, itemType.as(CdsSimpleType.class));
			}
		}
		throw new UnsupportedOperationException("Cannot parse " + type + " value: " + val);
	}

}