com.envimate.mapmate.deserialization.Deserializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapmate Show documentation
Show all versions of mapmate Show documentation
MapMate is a modern mapping framework in the scope of mapping data in
Json, XML, or YAML format into DTOs composed and vice versa.
/*
* Copyright (C) 2017 [Richard Hauswald, Nune Isabekyan] (envimate GmbH - https://envimate.com/)
*/
package com.envimate.mapmate.deserialization;
import com.envimate.mapmate.*;
import com.envimate.mapmate.infra.Marshaller;
import com.envimate.mapmate.validation.AggregatedValidationException;
import com.envimate.mapmate.validation.ExceptionTracker;
import com.envimate.mapmate.validation.ExceptionTracker.ExceptionEntry;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.regex.Pattern;
@SuppressWarnings({"unchecked", "CastToConcreteClass", "rawtypes"})
public final class Deserializer {
private static final Pattern COMPILE = Pattern.compile("\"");
private final Definitions definitions;
private final Marshaller marshaller;
Deserializer(final Marshaller marshaller, final Definitions definitions) {
this.marshaller = marshaller;
this.definitions = definitions;
}
public static DeserializerBuilder aDeserializer() {
return new DeserializerBuilder();
}
public T deserialize(final String input, final Class targetType) {
Objects.requireNonNull(input, "input cannot be null");
final ExceptionTracker exceptionTracker = new ExceptionTracker();
final T deserialized = deserialize(input, targetType, exceptionTracker);
final Set exceptions = exceptionTracker.resolve();
if (!exceptions.isEmpty()) {
throw AggregatedValidationException.fromSet(exceptions);
}
return deserialized;
}
private T deserialize(final String input, final Class targetType, final ExceptionTracker exceptionTracker) {
Objects.requireNonNull(input);
if (input.isEmpty()) {
return null;
}
final Definition definition = this.definitions.getDefinitionForType(targetType);
if (definition == null) {
throw DefinitionNotFoundException.definitionNotFound(targetType);
}
final String trimmedInput = input.trim();
if (targetType.isArray() || Collection.class.isAssignableFrom(targetType)) {
final List listInput = this.marshaller.unmarshal(trimmedInput, List.class);
return deserializeArray(listInput, targetType, exceptionTracker);
} else if (definition.isAggregate()) {
final Map parsedInput = this.marshaller.unmarshal(trimmedInput, Map.class);
return deserialize(parsedInput, targetType, exceptionTracker);
} else if (definition.isCustomType()) {
return deserializeCustomType(COMPILE.matcher(trimmedInput).replaceAll(""), targetType, exceptionTracker);
} else {
return null;
}
}
private T deserialize(final Map input, final Class targetType, final ExceptionTracker exceptionTracker) {
final Definition definition = this.definitions.getDefinitionForType(targetType);
return deserializeAggregate(input, (Aggregate) definition, exceptionTracker);
}
private T deserializeCustomType(final String input,
final Class> targetType,
final ExceptionTracker exceptionTracker) {
final Definition definition = this.definitions.getDefinitionForType(targetType);
final CustomType customType = (CustomType) definition;
return (T) deserializeCustomType(input, customType, exceptionTracker);
}
private T deserializeCustomType(final String input,
final CustomType definition,
final ExceptionTracker exceptionTracker) {
try {
return (T) definition.deserialize(input);
} catch (final FailedToDeserializeException e) {
exceptionTracker.track(e.getTargetCause());
return null;
}
}
@SuppressWarnings("ChainOfInstanceofChecks")
private T deserializeAggregate(final Map input,
final Aggregate definition,
final ExceptionTracker exceptionTracker) {
final Aggregate aggregate = definition;
if (aggregate.hasAdapter()) {
return (T) aggregate.getAdapter().deserialize(input, this, exceptionTracker);
}
final Method factoryMethod = aggregate.getFactoryMethod();
final Parameter[] parameters = factoryMethod.getParameters();
final Object[] arguments = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
final Parameter parameter = parameters[i];
final Object value = input.get(parameter.getName());
Object argument = null;
if (value instanceof String) {
argument = deserialize((String) value,
parameter.getType(),
exceptionTracker.stepInto(parameter.getName()));
} else if (value instanceof Map) {
argument = deserialize((Map) value,
parameter.getType(),
exceptionTracker.stepInto(parameter.getName()));
} else if (value instanceof List) {
argument = deserializeArray((List) value,
parameter.getType(),
exceptionTracker.stepInto(parameter.getName()));
}
arguments[i] = argument;
}
try {
return (T) factoryMethod.invoke(null, arguments);
} catch (final InvocationTargetException e) {
exceptionTracker.track(e.getTargetException());
return null;
} catch (IllegalArgumentException | IllegalAccessException | NullPointerException | ExceptionInInitializerError e) {
throw DeserializationException.fromException(e);
}
}
public T deserializeArray(final List input, final Class targetType, final ExceptionTracker exceptionTracker) {
final Object[] output = (Object[]) Array.newInstance(targetType.getComponentType(), input.size());
for (int i = 0; i < input.size(); i++) {
final Object value = input.get(i);
final String indexIndication = String.format("[%s]", i);
if (value instanceof Map) {
output[i] = deserialize(
(Map) input.get(i),
targetType.getComponentType(),
exceptionTracker.stepInto(indexIndication));
} else {
output[i] = deserialize(
(String) input.get(i),
targetType.getComponentType(),
exceptionTracker.stepInto(indexIndication));
}
}
return (T) output;
}
public Definitions getDefinitions() {
return this.definitions;
}
}