package net.tomatentum.marinara.wrapper; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import io.leangen.geantyref.GenericTypeReflector; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.util.LoggerUtil; import net.tomatentum.marinara.util.ReflectionUtil; public class IdentifierProvider { public static IdentifierProvider of(Converter... converter) { return new IdentifierProvider(Arrays.asList(converter)); } private Map, Converter> converter; private Logger logger = LoggerUtil.getLogger(getClass()); private IdentifierProvider(List> converter) { this.converter = new HashMap<>(); for (Converter conv : converter) { if (conv.getClass().getName().contains("$$Lambda")) throw new IllegalArgumentException("Lambdas cannot be used for IdentifierConverter because of Type erasure."); Type type = GenericTypeReflector.getExactSuperType(conv.getClass(), Converter.class); Type parameterType = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; if (!(parameterType instanceof Class)) throw new IllegalArgumentException("Only full Class types are supported by IdentiferConverters"); this.converter.put((Class) parameterType, conv); } } public InteractionIdentifier provide(Object context) { Type type = ReflectionUtil.getMostSpecificClass( converter.keySet().stream().filter(x -> x.isAssignableFrom(context.getClass())).toArray(Class[]::new), context.getClass()); if (type == null) logger.debug("No Identifier converter found for context {}", context.getClass().toString()); @SuppressWarnings("unchecked") Converter conv = (Converter) converter.get(type); return conv.convert(context); } @FunctionalInterface public interface Converter { InteractionIdentifier convert(T context); } public static class LambdaWrapper implements Converter { private Converter converter; LambdaWrapper(Converter converter) { this.converter = converter; } @Override public InteractionIdentifier convert(T context) { return this.converter.convert(context); } } }