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

net.amygdalum.testrecorder.deserializers.SimpleDeserializer Maven / Gradle / Ivy

There is a newer version: 0.10.5
Show newest version
package net.amygdalum.testrecorder.deserializers;

import static net.amygdalum.testrecorder.util.Types.baseType;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import net.amygdalum.testrecorder.runtime.GenericObject;
import net.amygdalum.testrecorder.runtime.GenericObjectException;
import net.amygdalum.testrecorder.types.DeserializationException;
import net.amygdalum.testrecorder.types.DeserializerContext;
import net.amygdalum.testrecorder.types.RoleVisitor;
import net.amygdalum.testrecorder.types.SerializedArgument;
import net.amygdalum.testrecorder.types.SerializedField;
import net.amygdalum.testrecorder.types.SerializedImmutableType;
import net.amygdalum.testrecorder.types.SerializedReferenceType;
import net.amygdalum.testrecorder.types.SerializedResult;
import net.amygdalum.testrecorder.types.SerializedValue;
import net.amygdalum.testrecorder.types.SerializedValueType;
import net.amygdalum.testrecorder.values.SerializedArray;
import net.amygdalum.testrecorder.values.SerializedEnum;
import net.amygdalum.testrecorder.values.SerializedImmutable;
import net.amygdalum.testrecorder.values.SerializedList;
import net.amygdalum.testrecorder.values.SerializedLiteral;
import net.amygdalum.testrecorder.values.SerializedMap;
import net.amygdalum.testrecorder.values.SerializedNull;
import net.amygdalum.testrecorder.values.SerializedObject;
import net.amygdalum.testrecorder.values.SerializedSet;

public class SimpleDeserializer implements RoleVisitor {

	private DeserializerContext context;
	private Map deserialized;

	public SimpleDeserializer(DeserializerContext context) {
		this.context = context;
		this.deserialized = new IdentityHashMap<>();
	}
	
	public DeserializerContext getContext() {
		return context;
	}

	@SuppressWarnings("unchecked")
	private  T fetch(SerializedValue key, Supplier supplier, Consumer init) {
		T value = (T) deserialized.get(key);
		if (value == null) {
			value = supplier.get();
			deserialized.put(key, value);
			init.accept(value);
		}
		return value;
	}

	@Override
	public Object visitField(SerializedField field) {
		throw new DeserializationException("failed deserializing: " + field);
	}

	@Override
	public Object visitArgument(SerializedArgument argument) {
		throw new DeserializationException("failed deserializing: " + argument);
	}

	@Override
	public Object visitResult(SerializedResult result) {
		throw new DeserializationException("failed deserializing: " + result);
	}

	@Override
	public Object visitReferenceType(SerializedReferenceType rt) {
		if (rt instanceof SerializedObject) {
			SerializedObject value = (SerializedObject) rt;
			try {
				Object object = fetch(value, () -> GenericObject.newInstance(baseType(value.getType())), base -> {
					for (SerializedField field : value.getFields()) {
						GenericObject.setField(base, field.getName(), field.getValue().accept(this));
					}
				});
				return object;
			} catch (GenericObjectException e) {
				throw new DeserializationException("failed deserializing: " + value, e);
			}
		} else if (rt instanceof SerializedList) {
			SerializedList value = (SerializedList) rt;
			List list = fetch(value, ArrayList::new, base -> {
				for (SerializedValue element : value) {
					base.add(element.accept(this));
				}
			});
			return list;
		} else if (rt instanceof SerializedMap) {
			SerializedMap value = (SerializedMap) rt;
			Map map = fetch(value, LinkedHashMap::new, base -> {
				for (Map.Entry entry : value.entrySet()) {
					Object k = entry.getKey().accept(this);
					Object v = entry.getValue().accept(this);
					base.put(k, v);
				}
			});
			return map;
		} else if (rt instanceof SerializedSet) {
			SerializedSet value = (SerializedSet) rt;
			Set set = fetch(value, LinkedHashSet::new, base -> {
				for (SerializedValue element : value) {
					base.add(element.accept(this));
				}
			});
			return set;
		} else if (rt instanceof SerializedArray) {
			SerializedArray value = (SerializedArray) rt;
			Class componentType = value.getRawType();
			SerializedValue[] rawArray = value.getArray();
			Object array = fetch(value, () -> Array.newInstance(componentType, rawArray.length), base -> {
				for (int i = 0; i < rawArray.length; i++) {
					Array.set(base, i, rawArray[i].accept(this));
				}
			});
			return array;
		} else if (rt instanceof SerializedNull) {
			return null;
		} else {
			return null;
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public Object visitImmutableType(SerializedImmutableType rt) {
		if (rt instanceof SerializedImmutable) {
			SerializedImmutable value = (SerializedImmutable) rt;
			return fetch(value, () -> value.getValue(), noInit());
		} else if (rt instanceof SerializedEnum) {
			SerializedEnum value = (SerializedEnum) rt;
			return Enum.valueOf((Class) baseType(value.getType()), value.getName());
		} else {
			return null;
		}
	}

	@Override
	public Object visitValueType(SerializedValueType value) {
		return fetch(value, () -> ((SerializedLiteral) value).getValue(), noInit());
	}

	private  Consumer noInit() {
		return base -> {
		};
	}

}