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

com.xlrit.gears.engine.meta.ObjectInfo Maven / Gradle / Ivy

package com.xlrit.gears.engine.meta;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.xlrit.gears.base.execution.Execution;
import com.xlrit.gears.engine.form.SubmitContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkNotNull;

public abstract class ObjectInfo implements TypeInfo, PathEval {
	private static final Logger LOG = LoggerFactory.getLogger(ObjectInfo.class);

	protected final String kind;
	protected final Class clazz;
	protected final List fields;
	protected final Constructor constructor; // can be null, in which case no new instance can be created

	protected ObjectInfo(String kind, Class clazz, List fields) {
		this.kind   = checkNotNull(kind);
		this.clazz  = checkNotNull(clazz);
		this.fields = checkNotNull(fields);
		this.constructor = findDefaultConstructor(clazz);
	}

	@Override
	public boolean isEntityReference() {
		return false;
	}

	@Override
	public Class getJavaType() {
		return clazz;
	}

	public String getKind() {
		return kind;
	}

	public Class getObjectClass() {
		return clazz;
	}

	public List getFields() {
		return fields;
	}

	private List getFieldNames() {
		return fields.stream()
			.map(BaseField::getName)
			.collect(Collectors.toList());
	}

	public F getField(String name) {
		return fields.stream()
			.filter(field -> name.equals(field.getName()))
			.findFirst()
			.orElseThrow(() -> new IllegalArgumentException("No field found with name '" + name + "' in object info for " + clazz.getSimpleName() + " " + getFieldNames()));
	}

	@Override
	public  R evaluate(String path, Execution execution, FieldFunction f) {
		String[] result = PathEval.extractName(path);
		String name = result[0]; String rest = result[1];
		return getField(name).evaluate(rest, execution, f);
	}

	@Override
	public String getTypeName() {
		return clazz.getName();
	}

	@Override
	public String getId(Object instance) {
		return null;
	}

	@Override
	public Object getInstance(String id) {
		throw new UnsupportedOperationException();
	}

	@Override
	public String print(Object obj, PrintOptions printOptions) {
		return String.valueOf(obj);
	}

	@Override
	public Object fromFormValue(JsonNode formValue, SubmitContext ctx) {
		throw new UnsupportedOperationException();
	}

	@Override
	public JsonNode toFormValue(Object obj, ObjectMapper objectMapper) {
		throw new UnsupportedOperationException();
	}

	public T newInstance() {
		if (constructor == null) {
			throw new RuntimeException("Unable to create new instance of " + clazz + ": no accessable default constructor");
		}
		try {
			return constructor.newInstance();
		}
		catch (ReflectiveOperationException e) {
			throw new RuntimeException("Unable to create new instance of " + clazz + ": " + e.getMessage(), e);
		}
	}

	@Override
	public JsonNode serialize(Object instance, ObjectMapper objectMapper, PrintOptions printOptions) {
		if (instance == null) return NullNode.instance;
		ObjectNode result = objectMapper.createObjectNode();
		result.set("__kind", TextNode.valueOf(kind));

		String id = getId(instance);
		if (id != null) {
			result.set("__id", TextNode.valueOf(id));
			result.set("__typeName", TextNode.valueOf(getTypeName()));
			if (printOptions != null) result.put("__text", print(instance, printOptions));
		}
		else {
			for (F field : fields) {
				String fieldName = field.getName();
				Object fieldValue = field.getValue(instance);
				result.set(fieldName, field.serialize(objectMapper, fieldValue, printOptions));
			}
		}
		LOG.debug("Object {} serialized as {}", instance, result);
		return result;
	}

	@Override
	public Object deserialize(JsonNode node, ObjectMapper objectMapper) {
		if (node == null || node.isNull()) return null;

		JsonNode idNode = node.get("__id");
		if (idNode != null) {
			Object instance = getInstance(idNode.asText());
			LOG.debug("JSON {} deserialized using reference {} as {}", node, idNode.asText(), instance);
			return instance;
		}
		else {
			Object obj = newInstance();
			for (F field : fields) {
				if (field.isReadOnly()) continue;
				JsonNode valueNode = node.get(field.getName());
				Object value = field.deserialize(objectMapper, valueNode);
				field.setValue(obj, value);
			}
			LOG.debug("JSON {} deserialized as {}", node, obj);
			return obj;
		}
	}

	private static  Constructor findDefaultConstructor(Class clazz) {
		try {
			Constructor constructor = clazz.getDeclaredConstructor();
			constructor.setAccessible(true);
			return constructor;
		}
		catch (ReflectiveOperationException e) {
			return null;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy