Use local copy of latest bndlib code for pre-release testing purposes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/lib/converter/Converter.java b/bundleplugin/src/main/java/aQute/lib/converter/Converter.java
new file mode 100644
index 0000000..abbbf9b
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/lib/converter/Converter.java
@@ -0,0 +1,364 @@
+package aQute.lib.converter;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.regex.*;
+
+import aQute.lib.base64.*;
+
+/**
+ * General Java type converter from an object to any type. Supports number
+ * conversion
+ * 
+ * @author aqute
+ * 
+ */
+@SuppressWarnings({ "unchecked", "rawtypes" }) public class Converter {
+	boolean	fatal	= true;
+
+	public <T> T convert(Class<T> type, Object o) throws Exception {
+		return (T) convert((Type) type, o);
+	}
+
+	public Object convert(Type type, Object o) throws Exception {
+		if (o == null)
+			return null; // compatible with any
+
+		Class resultType = getRawClass(type);
+		Class<?> actualType = o.getClass();
+		// Is it a compatible type?
+		if (resultType.isAssignableFrom(actualType))
+			return o;
+
+		// We can always make a string
+
+		if (resultType == String.class) {
+			if (actualType.isArray()) {
+				if (actualType == char[].class)
+					return new String((char[]) o);
+				if (actualType == byte[].class)
+					return Base64.encodeBase64((byte[]) o);
+				int l = Array.getLength(o);
+				StringBuilder sb = new StringBuilder("[");
+				String del = "";
+				for (int i = 0; i < l; i++) {
+					sb.append(del);
+					del = ",";
+					sb.append(convert(String.class, Array.get(o, i)));
+				}
+				sb.append("]");
+				return sb.toString();
+			}
+			return o.toString();
+		}
+
+		if (Collection.class.isAssignableFrom(resultType))
+			return collection(type, resultType, o);
+
+		if (Map.class.isAssignableFrom(resultType))
+			return map(type, resultType, o);
+
+		if (type instanceof GenericArrayType) {
+			GenericArrayType gType = (GenericArrayType) type;
+			return array(gType.getGenericComponentType(), o);
+		}
+
+		if (resultType.isArray()) {
+			if (actualType == String.class) {
+				String s = (String) o;
+				if (byte[].class == resultType)
+					return Base64.decodeBase64(s);
+
+				if (char[].class == resultType)
+					return s.toCharArray();
+			}
+			if (byte[].class == resultType) {
+				// Sometimes classes implement toByteArray
+				try {
+					Method m = actualType.getMethod("toByteArray");
+					if (m.getReturnType() == byte[].class)
+						return m.invoke(o);
+
+				} catch (Exception e) {
+					// Ignore
+				}
+			}
+
+			return array(resultType.getComponentType(), o);
+		}
+
+		// Simple type coercion
+
+		if (resultType == boolean.class || resultType == Boolean.class) {
+			if (actualType == boolean.class || actualType == Boolean.class)
+				return o;
+			Number n = number(o);
+			if (n != null)
+				return n.longValue() == 0 ? false : true;
+
+			resultType = Boolean.class;
+		} else if (resultType == byte.class || resultType == Byte.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.byteValue();
+			resultType = Byte.class;
+		} else if (resultType == char.class || resultType == Character.class) {
+			Number n = number(o);
+			if (n != null)
+				return (char) n.shortValue();
+			resultType = Character.class;
+		} else if (resultType == short.class || resultType == Short.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.shortValue();
+
+			resultType = Short.class;
+		} else if (resultType == int.class || resultType == Integer.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.intValue();
+
+			resultType = Integer.class;
+		} else if (resultType == long.class || resultType == Long.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.longValue();
+
+			resultType = Long.class;
+		} else if (resultType == float.class || resultType == Float.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.floatValue();
+
+			resultType = Float.class;
+		} else if (resultType == double.class || resultType == Double.class) {
+			Number n = number(o);
+			if (n != null)
+				return n.doubleValue();
+
+			resultType = Double.class;
+		}
+
+		assert !resultType.isPrimitive();
+
+		if (actualType == String.class) {
+			String input = (String) o;
+			if (resultType == char[].class)
+				return input.toCharArray();
+
+			if (resultType == byte[].class)
+				return Base64.decodeBase64(input);
+
+			if (Enum.class.isAssignableFrom(resultType)) {
+				return Enum.valueOf((Class<Enum>) resultType, input);
+			}
+			if (resultType == Pattern.class) {
+				return Pattern.compile(input);
+			}
+
+			try {
+				Constructor<?> c = resultType.getConstructor(String.class);
+				return c.newInstance(o.toString());
+			} catch (Throwable t) {
+			}
+			try {
+				Method m = resultType.getMethod("valueOf", String.class);
+				if (Modifier.isStatic(m.getModifiers()))
+					return m.invoke(null, o.toString());
+			} catch (Throwable t) {
+			}
+
+			if (resultType == Character.class && input.length() == 1)
+				return input.charAt(0);
+		}
+		Number n = number(o);
+		if (n != null) {
+			if (Enum.class.isAssignableFrom(resultType)) {
+				try {
+					Method values = resultType.getMethod("values");
+					Enum[] vs = (Enum[]) values.invoke(null);
+					int nn = n.intValue();
+					if (nn > 0 && nn < vs.length)
+						return vs[nn];
+				} catch (Exception e) {
+					// Ignore
+				}
+			}
+		}
+		return error("No conversion found for " + o.getClass() + " to " + type);
+	}
+
+	private Number number(Object o) {
+		if (o instanceof Number)
+			return (Number) o;
+
+		if (o instanceof Boolean)
+			return ((Boolean) o).booleanValue() ? 1 : 0;
+
+		if (o instanceof Character)
+			return (int) ((Character) o).charValue();
+
+		if (o instanceof String) {
+			String s = (String) o;
+			try {
+				return Double.parseDouble(s);
+			} catch (Exception e) {
+				// Ignore
+			}
+		}
+		return null;
+	}
+
+	private Collection collection(Type collectionType, Class<? extends Collection> rawClass,
+			Object o) throws Exception {
+		Collection collection;
+		if (rawClass.isInterface() || Modifier.isAbstract(rawClass.getModifiers())) {
+			if (rawClass.isAssignableFrom(ArrayList.class))
+				collection = new ArrayList();
+			else if (rawClass.isAssignableFrom(HashSet.class))
+				collection = new HashSet();
+			else if (rawClass.isAssignableFrom(TreeSet.class))
+				collection = new TreeSet();
+			else if (rawClass.isAssignableFrom(LinkedList.class))
+				collection = new LinkedList();
+			else if (rawClass.isAssignableFrom(Vector.class))
+				collection = new Vector();
+			else if (rawClass.isAssignableFrom(Stack.class))
+				collection = new Stack();
+			else if (rawClass.isAssignableFrom(ConcurrentLinkedQueue.class))
+				collection = new ConcurrentLinkedQueue();
+			else
+				return (Collection) error("Cannot find a suitable collection for the collection interface "
+						+ rawClass);
+		} else
+			collection = rawClass.newInstance();
+
+		Type subType = Object.class;
+		if (collectionType instanceof ParameterizedType) {
+			ParameterizedType ptype = (ParameterizedType) collectionType;
+			subType = ptype.getActualTypeArguments()[0];
+		}
+
+		Collection input = toCollection(o);
+
+		for (Object i : input)
+			collection.add(convert(subType, i));
+
+		return collection;
+	}
+
+	private Map map(Type mapType, Class<? extends Map<?, ?>> rawClass, Object o) throws Exception {
+		Map result;
+		if (rawClass.isInterface() || Modifier.isAbstract(rawClass.getModifiers())) {
+			if (rawClass.isAssignableFrom(HashMap.class))
+				result = new HashMap();
+			else if (rawClass.isAssignableFrom(TreeMap.class))
+				result = new TreeMap();
+			else if (rawClass.isAssignableFrom(ConcurrentHashMap.class))
+				result = new ConcurrentHashMap();
+			else
+				return (Map) error("Cannot find suitable map for map interface " + rawClass);
+		} else
+			result = rawClass.newInstance();
+
+		Map<?, ?> input = toMap(o);
+
+		Type keyType = Object.class;
+		Type valueType = Object.class;
+		if (mapType instanceof ParameterizedType) {
+			ParameterizedType ptype = (ParameterizedType) mapType;
+			keyType = ptype.getActualTypeArguments()[0];
+			valueType = ptype.getActualTypeArguments()[1];
+		}
+
+		for (Map.Entry<?, ?> entry : input.entrySet()) {
+			Object key = convert(keyType, entry.getKey());
+			Object value = convert(valueType, entry.getValue());
+			if (value == null)
+				return (Map) error("Key for map must not be null");
+			result.put(key, value);
+		}
+
+		return result;
+	}
+
+	public Object array(Type type, Object o) throws Exception {
+		Collection<?> input = toCollection(o);
+		Class<?> componentClass = getRawClass(type);
+		Object array = Array.newInstance(componentClass, input.size());
+
+		int i = 0;
+		for (Object next : input) {
+			Array.set(array, i++, convert(type, next));
+		}
+		return array;
+	}
+
+	private Class<?> getRawClass(Type type) {
+		if (type instanceof Class)
+			return (Class<?>) type;
+
+		if (type instanceof ParameterizedType)
+			return (Class<?>) ((ParameterizedType) type).getRawType();
+
+		if (type instanceof GenericArrayType) {
+			Type componentType = ((GenericArrayType) type).getGenericComponentType();
+			return Array.newInstance(getRawClass(componentType), 0).getClass();
+		}
+
+		if (type instanceof TypeVariable) {
+			Type componentType = ((TypeVariable) type).getBounds()[0];
+			return Array.newInstance(getRawClass(componentType), 0).getClass();
+		}
+
+		if (type instanceof WildcardType) {
+			Type componentType = ((WildcardType) type).getUpperBounds()[0];
+			return Array.newInstance(getRawClass(componentType), 0).getClass();
+		}
+
+		return Object.class;
+	}
+
+	public Collection<?> toCollection(Object o) {
+		if (o instanceof Collection)
+			return (Collection<?>) o;
+
+		if (o.getClass().isArray()) {
+			if (o.getClass().getComponentType().isPrimitive()) {
+				int length = Array.getLength(o);
+				List<Object> result = new ArrayList<Object>(length);
+				for (int i = 0; i < length; i++) {
+					result.add(Array.get(o, i));
+				}
+				return result;
+			}
+			return Arrays.asList((Object[]) o);
+		}
+
+		return Arrays.asList(o);
+	}
+
+	public Map<?, ?> toMap(Object o) throws Exception {
+		if (o instanceof Map)
+			return (Map<?, ?>) o;
+		Map result = new HashMap();
+		Field fields[] = o.getClass().getFields();
+		for (Field f : fields)
+			result.put(f.getName(), f.get(o));
+		if (result.isEmpty())
+			return null;
+
+		return result;
+	}
+
+	private Object error(String string) {
+		if (fatal)
+			throw new IllegalArgumentException(string);
+		return null;
+	}
+
+	public void setFatalIsException(boolean b) {
+		fatal = b;
+	}
+}
diff --git a/bundleplugin/src/main/java/aQute/lib/converter/packageinfo b/bundleplugin/src/main/java/aQute/lib/converter/packageinfo
new file mode 100644
index 0000000..3390555
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/lib/converter/packageinfo
@@ -0,0 +1 @@
+version 2.0.1