package fitnesse.slim.converters; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.lang.reflect.ParameterizedType; import java.util.*; import fitnesse.slim.Converter; public class ConverterRegistry { private static final Map<Class<?>, Converter<?>> converters = new HashMap<>(); private static Converter<Object> defaultConverter = new DefaultConverter(); static { addStandardConverters(); } private ConverterRegistry() { } public static void resetToStandardConverters() { converters.clear(); addStandardConverters(); } protected static void addStandardConverters() { addConverter(void.class, new VoidConverter()); addConverter(String.class, new StringConverter()); addConverter(Date.class, new DateConverter()); addConverter(Double.class, new DoubleConverter()); addConverter(double.class, new PrimitiveDoubleConverter()); addConverter(Integer.class, new IntConverter()); addConverter(int.class, new PrimitiveIntConverter()); addConverter(Character.class, new CharConverter()); addConverter(char.class, new PrimitiveCharConverter()); addConverter(Boolean.class, new BooleanConverter()); addConverter(boolean.class, new PrimitiveBooleanConverter()); try { addConverter(Map.class, new MapConverter()); } catch (NoClassDefFoundError e) { System.err.println("Slim Map converter not loaded: could not find class " + e.getMessage()); } } public static <T> Converter<T> getConverterForClass(Class<T> clazz) { return getConverterForClass(clazz, null); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static <T> Converter<T> getConverterForClass(Class<? extends T> clazz, ParameterizedType typedClazz) { //use converter set in registry if (converters.containsKey(clazz)) { return (Converter<T>) converters.get(clazz); } // use converter for superclass set in registry Class<?> superclass = clazz.getSuperclass(); while (superclass != null && !Object.class.equals(superclass)) { if (converters.containsKey(superclass)) { return (Converter<T>) converters.get(superclass); } superclass = superclass.getSuperclass(); } // use converter for implemented interface set in registry Converter<T> converterForInterface = getConverterForInterface(clazz); if (converterForInterface != null) { return converterForInterface; } //use property editor PropertyEditor pe = PropertyEditorManager.findEditor(clazz); if (pe != null && !"EnumEditor".equals(pe.getClass().getSimpleName())) { // com.sun.beans.EnumEditor and sun.beans.EnumEditor seem to be used in different usages. return new PropertyEditorConverter<>(pe); } //for enum, use generic enum converter if (clazz.isEnum()) { return new GenericEnumConverter(clazz); } //for array, use generic array converter if (clazz.isArray()) { Class<?> componentType = clazz.getComponentType(); Converter<?> converterForClass = getConverterForClassOrDefaultConverter(componentType); return new GenericArrayConverter(componentType, converterForClass); } //for collection, use generic collection converter if (Collection.class.isAssignableFrom(clazz)) { Class<?> componentType = typedClazz != null ? (Class<?>) typedClazz.getActualTypeArguments()[0] : String.class; Converter<?> converterForClass = getConverterForClassOrDefaultConverter(componentType); return new GenericCollectionConverter(clazz, converterForClass); } // last resort, see if there is a converter for Object return (Converter<T>) converters.get(Object.class); } protected static <T> Converter<T> getConverterForInterface(Class<?> clazz) { List<Class<?>> superInterfaces = new ArrayList<>(); Converter<T> converterForInterface = null; Class<?>[] interfaces = clazz.getInterfaces(); for (Class<?> interf : interfaces) { Class<?>[] s = interf.getInterfaces(); superInterfaces.addAll(Arrays.asList(s)); if (converters.containsKey(interf)) { converterForInterface = (Converter<T>) converters.get(interf); break; } } if (converterForInterface == null) { for (Class<?> supInterf : superInterfaces) { converterForInterface = getConverterForInterface(supInterf); if (converterForInterface != null) { break; } } if (converterForInterface == null) { Class<?> superclass = clazz.getSuperclass(); while (superclass != null && !Object.class.equals(superclass)) { converterForInterface = getConverterForInterface(superclass); if (converterForInterface != null) { break; } superclass = superclass.getSuperclass(); } } } return converterForInterface; } public static <T> void addConverter(Class<? extends T> clazz, Converter<T> converter) { converters.put(clazz, converter); } public static void removeConverter(Class<?> clazz) { converters.remove(clazz); } public static Map<Class<?>, Converter<?>> getConverters() { return Collections.unmodifiableMap(converters); } /* * PRIVATE */ public static Converter<?> getConverterForClassOrDefaultConverter(Class<?> clazz) { Converter<?> converter = getConverterForClass(clazz); if (converter == null) { converter = defaultConverter; } return converter; } }