RpcCastTools.java
package eu.javaexperience.rpc;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import eu.javaexperience.arrays.ArrayTools;
import eu.javaexperience.collection.map.SmallMap;
import eu.javaexperience.datareprez.ArrayLike;
import eu.javaexperience.datareprez.DataObject;
import eu.javaexperience.datareprez.DataReprezTools;
import eu.javaexperience.reflect.CastTo;
import eu.javaexperience.reflect.FieldSelectTools;
import eu.javaexperience.reflect.Mirror;
import eu.javaexperience.reflect.NotatedCaster;
import eu.javaexperience.text.Format;
public class RpcCastTools
{
public static NotatedCaster arrayCaster(final Class<?> cls)
{
if(cls.isArray())
{
final Class<?> component = cls.getComponentType();
final NotatedCaster c = tryCreateCaster(component);
if(null != c)
{
return new NotatedCaster()
{
@Override
public Object cast(Object in)
{
if(null == in)
{
return null;
}
if(cls.isAssignableFrom(in.getClass()))
{
return in;
}
//need convert
int len = tryGetLength(in);
if(-1 == len)
{
return null;
}
Object ret = Array.newInstance(component, len);
for(int i=0;i<len;++i)
{
Array.set(ret, i, c.cast(tryGetIndex(in, i)));
}
return ret;
}
@Override
public String getTypeShortName()
{
return c.getTypeShortName()+"[]";
}
@Override
public String getTypeFullQualifiedName()
{
return c.getTypeFullQualifiedName()+"[]";
}
};
}
}
return null;
}
protected static ConcurrentMap<Class, NotatedCaster> WELL_KNOWN_CASTERS = new ConcurrentHashMap<>();
static
{
WELL_KNOWN_CASTERS.put(Map.class, new NotatedCaster()
{
@Override
public Object cast(Object in)
{
if(in instanceof Map)
{
return in;
}
if(in instanceof DataObject)
{
return DataReprezTools.extractToJavaPrimitiveTypes(in);
}
SmallMap ret = new SmallMap<>();
try
{
Mirror.extractFieldsToMap(in, ret, FieldSelectTools.SELECT_ALL_INSTANCE_FIELD);
}
catch(Exception e){}
return ret;
}
@Override
public String getTypeShortName()
{
return "Map";
}
@Override
public String getTypeFullQualifiedName()
{
return "java.util.Map";
}
});
WELL_KNOWN_CASTERS.put(byte[].class, new NotatedCaster()
{
@Override
public Object cast(Object in)
{
if(in instanceof byte[])
{
return in;
}
if(in instanceof String)
{
return Format.base64Decode((String) in);
}
return null;
}
@Override
public String getTypeShortName()
{
return "byte[]";
}
@Override
public String getTypeFullQualifiedName()
{
return "byte[]";
}
});
}
protected static int tryGetLength(Object o)
{
if(null != o)
{
if(o.getClass().isArray())
{
return Array.getLength(o);
}
else if(o instanceof ArrayLike)
{
return ((ArrayLike)o).size();
}
else if(o instanceof List)
{
return ((List)o).size();
}
}
return -1;
}
protected static Object tryGetIndex(Object o, int i)
{
if(null != o)
{
if(o.getClass().isArray())
{
return Array.get(o, i);
}
else if(o instanceof ArrayLike)
{
return ((ArrayLike)o).get(i);
}
else if(o instanceof List)
{
return ((List)o).get(i);
}
}
return -1;
}
public static NotatedCaster tryCreateCaster(Type type)
{
Class cls = extractClass(type);
NotatedCaster ret = WELL_KNOWN_CASTERS.get(cls);
if(null != ret)
{
return ret;
}
if(cls.isArray())
{
NotatedCaster c = arrayCaster(cls);
if(null != c)
{
return c;
}
}
else
{
NotatedCaster c = CastTo.getCasterRestrictlyForTargetClass(cls);
if(null != c)
{
return c;
}
}
return null;
}
protected static ConcurrentMap<Class<?>, NotatedCaster> CASTERS = new ConcurrentHashMap<>();
public static NotatedCaster getDirectCaster(final Type type)
{
final Class<?> clss = extractClass(type);
NotatedCaster ret = CASTERS.get(clss);
if(null == ret)
{
ret = new NotatedCaster()
{
@Override
public Object cast(Object in)
{
if(null == in)
{
return null;
}
if(clss.isAssignableFrom(in.getClass()))
{
return in;
}
return null;
}
@Override
public String getTypeShortName()
{
return clss.getSimpleName();
}
@Override
public String getTypeFullQualifiedName()
{
return clss.getName();
}
};
CASTERS.put(clss, ret);
}
return ret;
}
public static Class<?> extractClass(Type type)
{
if(type instanceof Class)
{
return (Class<?>) type;
}
else if(type instanceof ParameterizedType)
{
ParameterizedType t = (ParameterizedType) type;
return extractClass(t.getRawType());
}
else if(type instanceof GenericArrayType)
{
GenericArrayType t = (GenericArrayType) type;
return extractClass(t.getGenericComponentType());
}
else if(type instanceof TypeVariable)
{
TypeVariable tv = (TypeVariable) type;
return extractClass(tv.getBounds()[0]);
}
else if(type instanceof GenericArrayType)
{
return extractClass(((GenericArrayType)type).getGenericComponentType());
}
else if(type instanceof WildcardType)
{
//WildcardType wt = (WildcardType) type;
}
else
{
//What's other?
}
throw new RuntimeException("Can't extract class of type: "+type);
}
}