Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
aQute.lib.converter.Converter Maven / Gradle / Ivy
Go to download
A main program (executable JAR) that will listen to port 29998. At first, it can only answer that it is an Envoy (a limited agent). The only function it supports is installing a -runpath. It will then create a framework + agent and transfer the connection to the just installed agent who will then install the bundles. This JAR is a main command for JPM called bndremote. In JPM, it will start up with debug enabled. This JAR does some highly complicated class loading wizardy to ensure that it does not enforce any constraints on the -runpath.
package aQute.lib.converter;
import static java.lang.invoke.MethodHandles.publicLookup;
import static java.lang.invoke.MethodType.methodType;
import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import aQute.lib.base64.Base64;
import aQute.lib.fileset.FileSet;
import aQute.lib.io.IO;
/**
* General Java type converter from an object to any type. Supports number
* conversion
*/
@SuppressWarnings({
"unchecked", "rawtypes"
})
public class Converter {
public interface Hook {
Object convert(Type dest, Object o) throws Exception;
}
boolean fatal = true;
Map hooks;
List allHooks;
File base = IO.work;
public T convert(Class type, Object o) throws Exception {
// Is it a compatible type?
if (o != null && type.isAssignableFrom(o.getClass()))
return (T) o;
return (T) convertT(type, o);
}
public T convert(TypeReference type, Object o) throws Exception {
return (T) convert(type.getType(), o);
}
public Object convert(Type type, Object o) throws Exception {
return convertT(type, o);
}
Object convertT(Type type, Object o) throws Exception {
Class resultType = getRawClass(type);
if (resultType == Optional.class) {
if (o == null)
return Optional.empty();
Object oo = convert(((ParameterizedType) type).getActualTypeArguments()[0], o);
return Optional.ofNullable(oo);
}
if (o == null) {
if (resultType.isPrimitive()) {
if (resultType == void.class)
return null;
if (resultType == boolean.class)
return false;
if (resultType == char.class)
return '\u0000';
return convert(type, 0);
}
return null; // compatible with any
}
if (allHooks != null) {
for (Hook hook : allHooks) {
Object r = hook.convert(type, o);
if (r != null)
return r;
}
}
if (hooks != null) {
Hook hook = hooks.get(type);
if (hook != null) {
Object value = hook.convert(type, o);
if (value != null)
return value;
}
}
Class> actualType = o.getClass();
// 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();
}
// or make a UUID
if (resultType == UUID.class) {
return UUID.fromString(o.toString());
}
//
// In case we have a Dictionary that is not also a map
// this is kind of opportune in OSGi because of the silly
// dictionaries we're still having
//
if (o instanceof Dictionary, ?> dict && !(o instanceof Map)) {
Map map = new HashMap<>();
Enumeration> e = dict.keys();
while (e.hasMoreElements()) {
Object k = e.nextElement();
Object v = dict.get(k);
map.put(k, v);
}
o = map;
}
if (Collection.class.isAssignableFrom(resultType))
return collection(type, resultType, o);
if (Map.class.isAssignableFrom(resultType))
return map(type, resultType, o);
if (type instanceof GenericArrayType gType) {
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 {
MethodHandle mh = publicLookup().findVirtual(actualType, "toByteArray", methodType(byte[].class));
return mh.invoke(o);
} catch (Error e) {
throw e;
} catch (Throwable e) {
// Ignore
}
}
return array(resultType.getComponentType(), o);
}
if (resultType.isAssignableFrom(o.getClass()))
return o;
if (Map.class.isAssignableFrom(actualType) && resultType.isInterface()) {
return proxy(resultType, (Map) o);
}
if (resultType == File.class && o instanceof String string) {
return IO.getFile(base, string);
}
// 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)) {
try {
return Enum.valueOf((Class) resultType, input);
} catch (Exception e) {
input = input.toUpperCase(Locale.ROOT);
String input2 = input.replace('_', '.');
try {
return Enum.valueOf((Class) resultType, input);
} catch (Exception ee) {
Class extends Enum> ec = resultType;
Enum[] enumConstants = ec.getEnumConstants();
if (enumConstants != null) {
for (Enum enm : enumConstants) {
String s = enm.toString();
if (s.equalsIgnoreCase(input))
return enm;
if (s.equalsIgnoreCase(input2))
return enm;
}
return null;
}
return null;
}
}
}
if (resultType == Pattern.class) {
return Pattern.compile(input);
}
if (resultType == URI.class) {
return new URI(sanitizeInputForURI(input));
}
try {
MethodHandle mh;
try {
mh = publicLookup().findStatic(resultType, "valueOf", methodType(resultType, String.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
mh = publicLookup().findConstructor(resultType, methodType(void.class, String.class));
}
return mh.invoke(o.toString());
} catch (Error e) {
throw e;
} 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 {
MethodHandle mh = publicLookup().findStatic(resultType, "values",
methodType(Array.newInstance(resultType, 0)
.getClass()));
Object[] vs = (Object[]) mh.invoke();
int nn = n.intValue();
if (nn > 0 && nn < vs.length)
return vs[nn];
} catch (Error e) {
throw e;
} catch (Throwable e) {
// Ignore
}
}
}
// Translate arrays with length 1 by picking the single element
if (actualType.isArray() && Array.getLength(o) == 1) {
return convert(type, Array.get(o, 0));
}
// Translate collections with size 1 by picking the single element
if (o instanceof Collection> col) {
if (col.size() == 1)
return convert(type, col.iterator()
.next());
}
if (o instanceof Map, ?> map) {
String key = null;
try {
if (resultType.isRecord()) {
int length = resultType.getRecordComponents().length;
Object[] arguments = new Object[length];
MethodType constructorType = methodType(void.class);
for (int i = 0; i < length; i++) {
RecordComponent c = resultType.getRecordComponents()[i];
Object value = map.get(c.getName());
arguments[i] = cnv(c.getGenericType(), value);
constructorType = constructorType.appendParameterTypes(c.getType());
}
MethodHandle mh = publicLookup().findConstructor(resultType, constructorType);
return mh.invokeWithArguments(arguments);
} else {
MethodHandle mh = publicLookup().findConstructor(resultType, methodType(void.class));
Object instance = mh.invoke();
for (Map.Entry e : map.entrySet()) {
key = (String) e.getKey();
try {
Field f = resultType.getField(key);
Object value = convert(f.getGenericType(), e.getValue());
mh = publicLookup().unreflectSetter(f);
if (isStatic(f)) {
mh.invoke(value);
} else {
mh.invoke(instance, value);
}
} catch (Exception ee) {
// We cannot find the key, so try the __extra field
mh = publicLookup().findGetter(resultType, "__extra", Map.class);
Map extra = (Map) mh.invoke(instance);
if (extra == null) {
extra = new HashMap<>();
mh = publicLookup().findSetter(resultType, "__extra", Map.class);
mh.invoke(instance, extra);
}
extra.put(key, convert(Object.class, e.getValue()));
}
}
return instance;
}
} catch (Error e) {
throw e;
} catch (Throwable e) {
return error(
"No conversion found for " + o.getClass() + " to " + type + ", error " + e + " on key " + key);
}
}
return error("No conversion found for " + o.getClass() + " to " + type);
}
private String sanitizeInputForURI(String input) {
int newline = input.indexOf("\n");
if (newline > -1)
return input.substring(0, newline)
.trim();
return input;
}
private Number number(Object o) {
if (o instanceof Number n)
return n;
if (o instanceof Boolean b)
return b.booleanValue() ? 1 : 0;
if (o instanceof Character c)
return (int) c.charValue();
if (o instanceof String s) {
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 = newInstance(rawClass);
}
Type subType = Object.class;
if (collectionType instanceof ParameterizedType ptype) {
subType = ptype.getActualTypeArguments()[0];
if (subType == File.class && o instanceof String string) {
FileSet tree = new FileSet(base, string);
return tree.getFiles();
}
}
Collection input = toCollection(o);
for (Object i : input)
collection.add(convert(subType, i));
return collection;
}
private static final MethodType defaultConstructor = methodType(void.class);
private static T newInstance(Class rawClass) throws Exception {
try {
return (T) publicLookup().findConstructor(rawClass, defaultConstructor)
.invoke();
} catch (Error | Exception e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private static boolean isStatic(Member m) {
return Modifier.isStatic(m.getModifiers());
}
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 = newInstance(rawClass);
}
Map, ?> input = toMap(o);
Type keyType = Object.class;
Type valueType = Object.class;
if (mapType instanceof ParameterizedType ptype) {
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 (key == null)
error("Key for map must not be null: " + input);
else
result.put(key, value);
}
return result;
}
public Object array(Type type, Object o) throws Exception {
if (type == File.class && o instanceof String string) {
FileSet tree = new FileSet(base, string);
return tree.getFiles()
.toArray(new File[0]);
}
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> ctype)
return ctype;
if (type instanceof ParameterizedType ptype)
return (Class>) ptype.getRawType();
if (type instanceof GenericArrayType gtype) {
Type componentType = gtype.getGenericComponentType();
return Array.newInstance(getRawClass(componentType), 0)
.getClass();
}
if (type instanceof TypeVariable ttype) {
Type componentType = ttype.getBounds()[0];
return Array.newInstance(getRawClass(componentType), 0)
.getClass();
}
if (type instanceof WildcardType wtype) {
Type componentType = wtype.getUpperBounds()[0];
return Array.newInstance(getRawClass(componentType), 0)
.getClass();
}
return Object.class;
}
public Collection> toCollection(Object o) {
if (o instanceof Collection> c)
return c;
if (o.getClass()
.isArray()) {
if (o.getClass()
.getComponentType()
.isPrimitive()) {
int length = Array.getLength(o);
List result = new ArrayList<>(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, ?> m)
return m;
Map result = new HashMap<>();
getFields(o.getClass()).forEach(f -> {
try {
MethodHandle mh = publicLookup().unreflectGetter(f);
result.put(f.getName(), mh.invoke(o));
} catch (Throwable e) {
throw new RuntimeException(e);
}
});
if (result.isEmpty()) {
return null;
}
return result;
}
private static Stream getFields(Class> c) {
return Stream.of(c.getFields())
.filter(field -> !(field.isEnumConstant() || field.isSynthetic() || isStatic(field)));
}
private Object error(String string) {
if (fatal)
throw new IllegalArgumentException(string);
return null;
}
public void setFatalIsException(boolean b) {
fatal = b;
}
public Converter hook(Type type, Hook hook) {
if (type != null) {
if (hooks == null)
hooks = new HashMap<>();
this.hooks.put(type, hook);
} else {
if (allHooks == null)
allHooks = new ArrayList<>();
allHooks.add(hook);
}
return this;
}
/**
* Convert a map to an interface.
*
* @param interfc
* @param properties
* @return proxy object for map
*/
public T proxy(Class interfc, final Map, ?> properties) {
return (T) Proxy.newProxyInstance(interfc.getClassLoader(), new Class[] {
interfc
}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName()
.equals("toString") && method.getParameterCount() == 0)
return properties + "'";
if (Object.class == method.getDeclaringClass()) {
MethodHandle mh = publicLookup().unreflect(method)
.bindTo(this);
return mh.invokeWithArguments(args);
}
Object o = properties.get(method.getName());
if (o == null)
o = properties.get(mangleMethodName(method.getName()));
if (o == null) {
if (args != null && args.length == 1) {
o = args[0];
} else {
o = method.getDefaultValue();
}
}
return convert(method.getGenericReturnType(), o);
}
});
}
public static String mangleMethodName(String id) {
char[] array = id.toCharArray();
int out = 0;
boolean changed = false;
for (int i = 0; i < array.length; i++) {
if (match("$$", array, i) || match("__", array, i)) {
array[out++] = array[i++];
changed = true;
} else if (match("$_$", array, i)) {
array[out++] = '-';
i += 2;
} else {
char c = array[i];
if (c == '_') {
array[out++] = '.';
changed = true;
} else if (c == '$') {
changed = true;
} else {
array[out++] = c;
}
}
}
if (id.length() != out || changed)
return new String(array, 0, out);
return id;
}
private static boolean match(String pattern, char[] array, int i) {
for (int j = 0; j < pattern.length(); j++, i++) {
if (i >= array.length)
return false;
if (pattern.charAt(j) != array[i])
return false;
}
return true;
}
public static T cnv(TypeReference tr, Object source) throws Exception {
return new Converter().convert(tr, source);
}
public static T cnv(Class tr, Object source) throws Exception {
return new Converter().convert(tr, source);
}
public static Object cnv(Type tr, Object source) throws Exception {
return new Converter().convert(tr, source);
}
/**
* Return if the class's instances can hold multiple values.
*
* @param c the class to test
* @return true if the class's instances can hold multiple values
*/
public static boolean isMultiple(Class> c) {
if (c.isArray())
return true;
if (Collection.class.isAssignableFrom(c))
return true;
if (Map.class.isAssignableFrom(c))
return true;
return false;
}
/**
* Return if the class's instances can hold multiple values.
*
* @param c the class to test
* @return true if the class's instances can hold multiple values
*/
public static boolean isMultiple(Type c) {
if (c instanceof Class> ctype)
return isMultiple(ctype);
if (c instanceof ParameterizedType ptype) {
Type rawType = ptype.getRawType();
if (rawType instanceof Class> ctype)
return isMultiple(ctype);
}
return false;
}
public void setBase(File base) {
this.base = base;
}
}