package com.bergerkiller.bukkit.common.conversion; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import com.bergerkiller.bukkit.common.conversion.type.ConversionTypes; import com.bergerkiller.bukkit.common.conversion.type.EmptyConverter; import com.bergerkiller.bukkit.common.conversion.type.EnumConverter; import com.bergerkiller.bukkit.common.conversion.type.ObjectArrayConverter; import com.bergerkiller.bukkit.common.internal.CommonPlugin; import com.bergerkiller.bukkit.common.utils.CommonUtil; import com.bergerkiller.bukkit.common.utils.LogicUtil; /** * Stores all available converters to convert Object values to a requested type */ public class Conversion extends ConversionTypes { private static final Map<Class<?>, Converter<Object>> converters = new ConcurrentHashMap<Class<?>, Converter<Object>>(); static { try { registerAll(ConversionTypes.class); ConversionPairs.class.getModifiers(); // Load this class } catch (Throwable t) { CommonPlugin.LOGGER_CONVERSION.log(Level.SEVERE, "Failed to initialize default converters", t); } } /** * Registers all available static convertor constants found in the Class or enum * * @param convertorConstants class container to register */ public static void registerAll(Class<?> convertorConstants) { for (Object convertor : CommonUtil.getClassConstants(convertorConstants, Converter.class)) { if (convertor instanceof Converter) { register((Converter<?>) convertor); } } } /** * Registers a converter so it can be used to convert to the output type it represents. * If the converter does not support registration, it is ignored * * @param converter to register */ @SuppressWarnings("unchecked") public static void register(Converter<?> converter) { if (!converter.isRegisterSupported()) { return; } converters.put(converter.getOutputType(), (Converter<Object>) converter); } /** * Obtains the converter used to convert to the type specified<br> * If none is available yet for the type, a new one is created * * @param type to convert to * @return converter */ @SuppressWarnings({"unchecked", "rawtypes"}) public static <T> Converter<T> getConverter(Class<T> type) { if (type.isPrimitive()) { type = (Class<T>) LogicUtil.getBoxedType(type); } Converter<T> converter = (Converter<T>) converters.get(type); if (converter == null) { if (type.isArray()) { // Maybe converting to an Object array of a certain component type? // Note: Primitives are already dealt with and registered in the map final Class<?> componentType = type.getComponentType(); if (!componentType.isPrimitive()) { // Use the ObjectArrayConvertor to deal with this converter = new ObjectArrayConverter(componentType); } } else if (type.isEnum()) { // Converting to an enum type - construct a new EnumConverter converter = new EnumConverter<T>(type); } else { // Maybe the requested type is an extension? // If so, put a new casting converter in place to deal with it for (Converter<Object> conv : converters.values()) { if (conv.isCastingSupported() && conv.getOutputType().isAssignableFrom(type)) { converter = new CastingConverter(type, conv); break; } } } // Resolve to the default casting-based converter if not found if (converter == null) { converter = new EmptyConverter(type); } // Found. Put into map for faster look-up converters.put(type, (Converter<Object>) converter); } return (Converter<T>) converter; } /** * Converts an object to the given type using previously registered converters * * @param value to convert * @param def value to return on failure (can not be null) * @return the converted value */ @SuppressWarnings("unchecked") public static <T> T convert(Object value, T def) { return convert(value, (Class<T>) def.getClass(), def); } /** * Converts an object to the given type using previously registered converters * * @param value to convert * @param type to convert to * @return the converted value, or null on failure */ public static <T> T convert(Object value, Class<T> type) { return convert(value, type, null); } /** * Converts an object to the given type using previously registered converters * * @param value to convert * @param type to convert to * @param def value to return on failure * @return the converted value */ public static <T> T convert(Object value, Class<T> type, T def) { if (value == null) { return def; } final Class<?> valueType = value.getClass(); if (type.isAssignableFrom(valueType)) { return type.cast(value); } return getConverter(type).convert(value, def); } }