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

org.emfjson.jackson.databind.property.EObjectPropertyMap Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
package org.emfjson.jackson.databind.property;

import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import org.eclipse.emf.ecore.*;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.emfjson.jackson.annotations.EcoreIdentityInfo;
import org.emfjson.jackson.annotations.EcoreReferenceInfo;
import org.emfjson.jackson.annotations.EcoreTypeInfo;
import org.emfjson.jackson.annotations.JsonAnnotations;
import org.emfjson.jackson.databind.EMFContext;
import org.emfjson.jackson.databind.type.EcoreTypeFactory;
import org.emfjson.jackson.module.EMFModule;

import java.util.*;

import static org.emfjson.jackson.annotations.JsonAnnotations.getElementName;
import static org.emfjson.jackson.module.EMFModule.Feature.OPTION_SERIALIZE_TYPE;
import static org.emfjson.jackson.module.EMFModule.Feature.OPTION_USE_ID;

public class EObjectPropertyMap {

	public static class Builder {

		private final Map cache = new WeakHashMap<>();

		private final EcoreIdentityInfo identityInfo;
		private final EcoreTypeInfo typeInfo;
		private final EcoreReferenceInfo referenceInfo;
		private final int features;

		public Builder(EcoreIdentityInfo identityInfo, EcoreTypeInfo typeInfo, EcoreReferenceInfo referenceInfo, int features) {
			this.identityInfo = identityInfo;
			this.typeInfo = typeInfo;
			this.referenceInfo = referenceInfo;
			this.features = features;
		}

		public static Builder from(EMFModule module, int features) {
			return new Builder(module.getIdentityInfo(), module.getTypeInfo(), module.getReferenceInfo(), features);
		}

		public EObjectPropertyMap construct(DatabindContext ctxt, EClass type) {
			if (type == null) {
				return new EObjectPropertyMap(null, collectProperties(ctxt, null));
			}

			EObjectPropertyMap propertyMap = cache.get(type);
			if (propertyMap == null) {
				cache.put(type, propertyMap = new EObjectPropertyMap(type, collectProperties(ctxt, type)));
			}
			return propertyMap;
		}

		boolean isFeatureMapEntry(EStructuralFeature feature) {
			EAnnotation annotation = feature.getEAnnotation(ExtendedMetaData.ANNOTATION_URI);

			return annotation != null && annotation.getDetails().containsKey("group");
		}

		boolean isCandidate(EAttribute attribute) {
			return isFeatureMapEntry(attribute) || (
					!FeatureMapUtil.isFeatureMap(attribute) &&
							!(attribute.isDerived() || attribute.isTransient()) &&
							!JsonAnnotations.shouldIgnore(attribute));
		}

		boolean isCandidate(EReference eReference) {
			if (isFeatureMapEntry(eReference)) {
				return true;
			}
			if (FeatureMapUtil.isFeatureMap(eReference)) {
				return false;
			}
			if (eReference.isTransient() || JsonAnnotations.shouldIgnore(eReference)) {
				return false;
			}

			EReference opposite = eReference.getEOpposite();
			return !(opposite != null && opposite.isContainment());
		}

		Map collectProperties(DatabindContext ctxt, EClass type) {
			final EcoreTypeFactory factory = EMFContext.getTypeFactory(ctxt);
			final Map properties = new LinkedHashMap<>();

			if (OPTION_USE_ID.enabledIn(features)) {
				properties.put(identityInfo.getProperty(), new EObjectIdentityProperty(identityInfo));
			}

			if (OPTION_SERIALIZE_TYPE.enabledIn(features)) {
				EObjectProperty property = getTypeProperty(type);
				properties.put(property.getFieldName(), property);
			}

			properties.put(referenceInfo.getProperty(), new EObjectReferenceProperty(referenceInfo));

			if (type != null) {
				for (EAttribute attribute : type.getEAllAttributes()) {
					if (isCandidate(attribute)) {
						JavaType javaType = factory.typeOf(ctxt, type, attribute);
						if (javaType != null) {
							properties.put(getElementName(attribute), new EObjectFeatureProperty(attribute, javaType, features));
						}
					}
				}

				for (EReference reference : type.getEAllReferences()) {
					if (isCandidate(reference)) {
						JavaType javaType = factory.typeOf(ctxt, type, reference);
						if (javaType != null) {
							properties.put(getElementName(reference), new EObjectFeatureProperty(reference, javaType, features));
						}
					}
				}

				for (EOperation operation : type.getEAllOperations()) {
					EAnnotation annotation = operation.getEAnnotation("JsonProperty");
					if (annotation != null && operation.getEParameters().isEmpty()) {
						properties.put(getElementName(operation), new EObjectOperationProperty(getElementName(operation), operation));
					}
				}
			}

			return properties;
		}

		private EObjectProperty getTypeProperty(EClass type) {
			if (type != null && !JsonAnnotations.shouldIgnoreType(type)) {
				String property = JsonAnnotations.getTypeProperty(type);
				if (property != null) {
					return new EObjectTypeProperty(new EcoreTypeInfo(property));
				} else {
					return new EObjectTypeProperty(typeInfo);
				}
			} else {
				return new EObjectTypeProperty(typeInfo);
			}
		}

		public EObjectPropertyMap constructDefault(DatabindContext ctxt) {
			return construct(ctxt, null);
		}

		public EObjectPropertyMap find(DeserializationContext ctxt, EClass defaultType, Iterator fields) {
			List types = EMFContext.allSubTypes(ctxt, defaultType);
			Map properties = new HashMap<>();
			for (EClass type : types) {
				EObjectProperty p = getTypeProperty(type);
				properties.put(p.getFieldName(), type);
			}

			while (fields.hasNext()) {
				String field = fields.next();

				if (properties.containsKey(field)) {
					return construct(ctxt, properties.get(field));
				}
			}

			return construct(ctxt, defaultType);
		}

	}

	private final Map properties;
	private final EClass type;

	EObjectPropertyMap(EClass type, Map properties) {
		this.type = type;
		this.properties = properties;
	}

	public EObjectProperty findProperty(String field) {
		return properties.get(field);
	}

	public Iterable getProperties() {
		return properties.values();
	}

	public EObjectTypeProperty getTypeProperty() {
		for (EObjectProperty property : properties.values()) {
			if (property instanceof EObjectTypeProperty) {
				return (EObjectTypeProperty) property;
			}
		}
		return null;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		EObjectPropertyMap that = (EObjectPropertyMap) o;
		return Objects.equals(properties, that.properties) &&
				Objects.equals(type, that.type);
	}

	@Override
	public int hashCode() {
		return Objects.hash(properties, type);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy