package com.github.rmannibucau.cdi.configuration.factory; import com.github.rmannibucau.cdi.configuration.ConfigurationException; import com.github.rmannibucau.cdi.configuration.loader.ClassLoaders; import org.apache.deltaspike.core.api.config.ConfigResolver; import org.apache.deltaspike.core.api.provider.BeanProvider; import javax.xml.namespace.QName; import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public final class Converter { private static final String REF_PREFIX = "ref:"; private Converter() { // no-op } public static Object convertTo(final Type type, final String rawValue) { final String value = interpolate(rawValue); if (value == null || String.class.equals(type) || Object.class.equals(type)) { return value; } if (Class.class.isInstance(type)) { final Class<?> rawType = Class.class.cast(type); if (List.class.isAssignableFrom(rawType)) { return Arrays.asList(toArray(String.class, value)); } if (Set.class.isAssignableFrom(rawType)) { final Set<Object> set = new HashSet<Object>(); set.addAll(Arrays.asList(toArray(String.class, value))); return set; } if (Map.class.isAssignableFrom(rawType)) { return toMap(value, String.class, String.class); } if (Integer.class.equals(type) || Integer.TYPE.equals(type)) { return Integer.parseInt(value); } if (Long.class.equals(type) || Long.TYPE.equals(type)) { return Long.parseLong(value); } if (Short.class.equals(type) || Short.TYPE.equals(type)) { return Short.parseShort(value); } if (Boolean.class.equals(type) || Boolean.TYPE.equals(type)) { return Boolean.parseBoolean(value); } if (Double.class.equals(type) || Double.TYPE.equals(type)) { return Double.parseDouble(value); } if (Float.class.equals(type) || Float.TYPE.equals(type)) { return Float.parseFloat(value); } if (rawType.isArray()) { final Class<?> componentType = rawType.getComponentType(); return toArray(componentType, value); } if (URL.class.equals(rawType)) { try { return new URL(value); } catch (final MalformedURLException e) { throw new ConfigurationException(e); } } if (URI.class.equals(rawType)) { try { return new URL(value).toURI(); } catch (final Exception e) { throw new ConfigurationException(e); } } if (QName.class.equals(rawType)) { final int endIdx = value.indexOf("}"); if (value.startsWith("{") && endIdx > 0) { return new QName(value.substring(1, endIdx), value.substring(endIdx + 1)); } return new QName(value); } if (Class.class.equals(rawType)) { try { return ClassLoaders.tccl().loadClass(value); } catch (final ClassNotFoundException e) { throw new ConfigurationException(e); } } } if (ParameterizedType.class.isInstance(type)) { final ParameterizedType parameterizedType = ParameterizedType.class.cast(type); final Class<?> rawType = Class.class.cast(parameterizedType.getRawType()); if (Class.class.equals(rawType)) { try { return ClassLoaders.tccl().loadClass(value); } catch (final ClassNotFoundException e) { throw new ConfigurationException(e); } } final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); final Class<?> param; if (actualTypeArguments.length == 0 || WildcardType.class.isInstance(actualTypeArguments[0])) { param = Object.class; } else { param = (Class<?>) actualTypeArguments[0]; } if (List.class.isAssignableFrom(rawType)) { return Arrays.asList(toArray(param, value)); } if (Set.class.isAssignableFrom(rawType)) { final Set<Object> set = new HashSet<Object>(); set.addAll(Arrays.asList(toArray(param, value))); return set; } if (Map.class.isAssignableFrom(rawType)) { final Class<?> valueType = (Class<?>) actualTypeArguments[1]; return toMap(value, param, valueType); } } if (value.startsWith("ref:")) { return BeanProvider.getContextualReference(value.substring(REF_PREFIX.length())); } throw new ConfigurationException("Can't convert '" + value + "' to " + type); } private static String interpolate(final String rawValue) { if (rawValue == null) { return null; } if (rawValue.startsWith("${") && rawValue.endsWith("}")) { return ConfigResolver.getPropertyValue(rawValue.substring(2, rawValue.length() - 1), rawValue); } return rawValue; } private static Map<?, ?> toMap(final String value, final Class<?> param, final Class<?> valueType) { final Map<Object, Object> map = new HashMap<Object, Object>(); final String[] raw = value.split(","); for (final String aRaw : raw) { final String[] kv = aRaw.split("="); if (kv.length == 1) { map.put(convertTo(param, aRaw), null); } else { map.put(convertTo(param, kv[0]), convertTo(valueType, kv[1])); } } return map; } private static Object[] toArray(final Class<?> componentType, final String value) { final String[] raw = value.split(","); final Object array = Array.newInstance(componentType, raw.length); for (int i = 0; i < raw.length; i++) { Array.set(array, i, convertTo(componentType, raw[i])); } return Object[].class.cast(array); } }