com.sap.cds.impl.CdsDataImpl Maven / Gradle / Ivy
/************************************************************************
* © 2022-2023 SAP SE or an SAP affiliate company. All rights reserved. *
************************************************************************/
package com.sap.cds.impl;
import java.lang.reflect.Proxy;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.cds.CdsData;
import com.sap.cds.impl.ProxyCreator.MapProxy;
import com.sap.cds.impl.parser.token.Jsonizer;
import com.sap.cds.util.DataUtils;
public class CdsDataImpl extends AbstractMap implements CdsData {
private static final String FOR_REMOVAL = "forRemoval";
private static final Map EMPTY_MAP = Map.of();
protected final Map data;
protected Map metadata;
protected CdsDataImpl(Map data, Map metadata) {
this.data = data;
this.metadata = metadata;
}
protected CdsDataImpl(Map data) {
this(data, EMPTY_MAP);
}
public static CdsData create(Map data) {
if (data instanceof CdsData cdsData) {
return cdsData;
}
return new CdsDataImpl(data);
}
public static CdsDataImpl copy(Map other) {
Map metadata = metadataOf(other);
return new CdsDataImpl(copyMap(other), metadata == EMPTY_MAP ? EMPTY_MAP : copyMap(metadata));
}
static Map metadataOf(Map other) {
if (other instanceof CdsDataImpl otherCdsData) {
return otherCdsData.metadata;
} else if (other instanceof LazyRowImpl otherLazyRow) {
return metadataOf(otherLazyRow.delegate());
} else if (Proxy.isProxyClass(other.getClass())
&& Proxy.getInvocationHandler(other) instanceof MapProxy otherProxy) {
// unbox proxy and copy underlying data map
return metadataOf(otherProxy.getCdsData());
}
return EMPTY_MAP;
}
private static Map copyMap(Map original) {
return original.entrySet().stream().collect(CdsData::create,
(m, e) -> m.put(e.getKey(), copyIfListOrMap(e.getValue())), CdsData::putAll);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object copyIfListOrMap(Object original) {
if (original instanceof List list) {
return CdsListImpl.copy(list);
}
if (original instanceof Map) {
return CdsDataImpl.copy((Map) original);
}
return original; // expected to be immutable
}
@Override
@SuppressWarnings("unchecked")
public T getMetadata(String key) {
return (T) metadata.get(key);
}
@Override
@SuppressWarnings("unchecked")
public T putMetadata(String key, T value) {
if (metadata == EMPTY_MAP) {
// not thread-safe, but assumed to be okay
metadata = new HashMap<>();
}
return (T) metadata.put(key, value);
}
@Override
@SuppressWarnings("unchecked")
public CdsData forRemoval(boolean remove) {
putMetadata(FOR_REMOVAL, remove);
return this;
}
@Override
public boolean isForRemoval() {
return Boolean.TRUE.equals(getMetadata(FOR_REMOVAL));
}
@Override
public boolean containsPath(String path) {
return DataUtils.containsKey(data, path);
}
@Override
public Set> entrySet() {
return data.entrySet();
}
@Override
public Object put(String key, Object value) {
return data.put(key, value);
}
@Override
public T removePath(String path) {
@SuppressWarnings("unchecked")
T value = (T) DataUtils.removePath(data, path, true);
return decorateMap(value);
}
@Override
public T putPath(String path, T value) {
@SuppressWarnings("unchecked")
T oldValue = (T) DataUtils.putPath(data, path, value);
return decorateMap(oldValue);
}
@Override
public T putPathIfAbsent(String path, T value) {
T v = getPath(path);
if (v == null) {
putPath(path, value);
}
return v;
}
@Override
public Object get(Object key) {
Object value = data.get(key);
return decorateMap(value);
}
@Override
public T getPath(String path) {
return getPathOrDefault(path, null);
}
@Override
public T getPathOrDefault(String path, T defaultValue) {
T value = DataUtils.getPathOrDefault(data, path, defaultValue);
return decorateMap(value);
}
@SuppressWarnings("unchecked")
private T decorateMap(T value) {
if (value instanceof Map map) {
return (T) decorate(map);
}
return value;
}
protected CdsData decorate(Map map) {
if (map instanceof CdsData data) {
return data;
}
return new CdsDataImpl(map);
}
@Override
public String toJson() {
return Jsonizer.json(this);
}
public static class Factory implements CdsData.Factory {
@Override
public CdsData create() {
return new CdsDataImpl(new HashMap<>());
}
@Override
public CdsData create(Map data) {
return CdsDataImpl.create(data);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy