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

net.amygdalum.testrecorder.DefaultSerializerSession Maven / Gradle / Ivy

package net.amygdalum.testrecorder;

import static java.util.stream.Collectors.toList;
import static net.amygdalum.testrecorder.asm.ByteCode.classFrom;
import static net.amygdalum.testrecorder.util.Lambdas.isSerializableLambda;
import static net.amygdalum.testrecorder.util.Reflections.accessing;
import static net.amygdalum.testrecorder.util.Types.baseType;
import static net.amygdalum.testrecorder.util.Types.isLiteral;
import static net.amygdalum.testrecorder.util.Types.serializableOf;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import net.amygdalum.testrecorder.profile.Classes;
import net.amygdalum.testrecorder.profile.Excluded;
import net.amygdalum.testrecorder.profile.Facade;
import net.amygdalum.testrecorder.profile.Fields;
import net.amygdalum.testrecorder.types.AnalyzedObject;
import net.amygdalum.testrecorder.types.Profile;
import net.amygdalum.testrecorder.types.SerializedReferenceType;
import net.amygdalum.testrecorder.types.SerializedValue;
import net.amygdalum.testrecorder.types.SerializerSession;
import net.amygdalum.testrecorder.util.Lambdas;

public class DefaultSerializerSession implements SerializerSession {

	private Map serialized;
	private Map, Profile> profiles;

	private List classExclusions;
	private List classFacades;
	private List fieldExclusions;
	private List fieldFacades;
	private Map facaded;

	public DefaultSerializerSession() {
		serialized = new IdentityHashMap<>();
		profiles = new LinkedHashMap<>();
		facaded = new IdentityHashMap<>();
		classExclusions = new ArrayList<>();
		classFacades = new ArrayList<>();
		fieldExclusions = new ArrayList<>();
		fieldFacades = new ArrayList<>();
	}

	public DefaultSerializerSession withClassExclusions(List classExclusions) {
		this.classExclusions.addAll(classExclusions);
		return this;
	}

	public DefaultSerializerSession withClassFacades(List classFacades) {
		this.classFacades.addAll(classFacades);
		return this;
	}

	public DefaultSerializerSession withFieldExclusions(List fieldExclusions) {
		this.fieldExclusions.addAll(fieldExclusions);
		return this;
	}

	public DefaultSerializerSession withFieldFacades(List fieldFacades) {
		this.fieldFacades.addAll(fieldFacades);
		return this;
	}

	@Override
	public synchronized Profile log(Type type) {
		return profiles.computeIfAbsent(baseType(type), (t) -> Profile.start(t));
	}

	@Override
	public synchronized List dumpProfiles() {
		List dump = profiles.values().stream()
			.sorted()
			.limit(20)
			.collect(toList());
		profiles = new LinkedHashMap<>();
		return dump;
	}

	@Override
	public SerializedValue find(Object object) {
		return serialized.get(object);
	}

	@Override
	public SerializedValue ref(Object object, Type type) {
		SerializedValue serializedValue = find(object);
		if (serializedValue instanceof SerializedReferenceType && type != null && !baseType(type).isSynthetic()) {
			SerializedReferenceType serializedReferenceType = (SerializedReferenceType) serializedValue;
			serializedReferenceType.useAs(serializableOf(type));
		}
		return serializedValue;
	}

	@Override
	public void resolve(Object object, SerializedValue value) {
		serialized.put(object, value);
	}

	@Override
	public boolean excludes(Field field) {
		if (field.isAnnotationPresent(Excluded.class)) {
			return true;
		}
		boolean excluded = fieldExclusions.stream()
			.anyMatch(exclusion -> exclusion.matches(field));
		if (!excluded) {
			Class type = field.getType();
			excluded = classExclusions.stream()
				.anyMatch(exclusion -> exclusion.matches(type));
		}
		return excluded;
	}

	public AnalyzedObject analyze(Object object) {
		if (object == null) {
			return new AnalyzedObject(null);
		}
		Class clazz = object.getClass();
		if (isLiteral(clazz)) {
			return new AnalyzedObject(clazz, object);
		}
		if (isSerializableLambda(clazz)) {
			SerializedLambda lambda = Lambdas.serializeLambda(object);
			Class type = classFrom(lambda.getFunctionalInterfaceClass(), clazz.getClassLoader());
			return new AnalyzedObject(object, type, lambda);
		}
		if (facades(clazz)) {
			facaded.put(object, object);
		}
		Class objectClass = clazz;
		while (objectClass != Object.class) {
			for (Field field : objectClass.getDeclaredFields()) {
				if (facades(field)) {
					try {
						Object obj = accessing(field).call(f -> f.get(object));
						facaded.put(obj, obj);
					} catch (ReflectiveOperationException e) {
						continue;
					}
				}
			}
			objectClass = objectClass.getSuperclass();
		}
		return new AnalyzedObject(clazz, object);
	}

	private boolean facades(Field field) {
		if (field.isAnnotationPresent(Facade.class)) {
			return true;
		}
		return fieldFacades.stream()
			.anyMatch(facade -> facade.matches(field));
	}

	private boolean facades(Class clazz) {
		if (clazz.isAnnotationPresent(Facade.class)) {
			return true;
		}
		return classFacades.stream()
			.anyMatch(facade -> facade.matches(clazz));
	}

	@Override
	public boolean excludes(Class clazz) {
		if (clazz.isAnnotationPresent(Excluded.class)) {
			return true;
		}
		return classExclusions.stream()
			.anyMatch(exclusion -> exclusion.matches(clazz));
	}

	@Override
	public boolean facades(Object object) {
		return facaded.containsKey(object);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy