package org.simpleflatmapper.reflect.meta; import org.simpleflatmapper.converter.ConverterService; import org.simpleflatmapper.reflect.instantiator.ExecutableInstantiatorDefinition; import org.simpleflatmapper.reflect.InstantiatorDefinition; import org.simpleflatmapper.reflect.ReflectionService; import org.simpleflatmapper.util.Consumer; import org.simpleflatmapper.util.Predicate; import org.simpleflatmapper.util.TypeHelper; import org.simpleflatmapper.converter.Converter; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class MapClassMeta<M extends Map<K, V>, K, V> implements ClassMeta<M> { private final ReflectionService reflectionService; private final Converter<? super CharSequence, ? extends K> keyConverter; private final ClassMeta<V> valueClassMeta; private final Type type; private final Constructor<?> constructor; public MapClassMeta(Type type, Type keyType, Type valueType, ReflectionService reflectionService) { this.type = type; this.keyConverter = ConverterService.getInstance().findConverter(CharSequence.class, keyType); if (keyConverter == null) { throw new IllegalArgumentException("Unsupported key type " + keyType); } this.reflectionService = reflectionService; this.valueClassMeta = reflectionService.getClassMeta(valueType); this.constructor = getConstructor(type); } private Constructor<?> getConstructor(Type type) { Class<?> implClass = findMapImpl(type); try { return implClass.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("No empty constructor for " + implClass); } } private Class<?> findMapImpl(Type type) { Class<?> clazz = TypeHelper.toClass(type); if (clazz.isInterface()) { if (Map.class.equals(clazz)) { return HashMap.class; } else if(ConcurrentMap.class.equals(clazz)) { return ConcurrentHashMap.class; } } else if (!Modifier.isAbstract(clazz.getModifiers())) { return clazz; } throw new IllegalArgumentException("No known Map impl for " + type); } @Override public ReflectionService getReflectionService() { return reflectionService; } @Override public PropertyFinder<M> newPropertyFinder(Predicate<PropertyMeta<?, ?>> propertyFilter) { return new MapPropertyFinder<M, K, V>(this, valueClassMeta, keyConverter, propertyFilter); } @Override public Type getType() { return type; } @Override public List<InstantiatorDefinition> getInstantiatorDefinitions() { return Arrays.<InstantiatorDefinition>asList(new ExecutableInstantiatorDefinition(constructor)); } @Override public void forEachProperties(Consumer<? super PropertyMeta<M, ?>> consumer) { throw new UnsupportedOperationException("Cannot list properties as non static"); } }