TargetObject.java
package eu.linuxengineering.zabbix.api;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.json.JSONArray;
import eu.javaexperience.arrays.ArrayTools;
import eu.javaexperience.collection.enumerations.EnumTools;
import eu.javaexperience.datareprez.DataArray;
import eu.javaexperience.datareprez.DataCommon;
import eu.javaexperience.datareprez.DataObject;
import eu.javaexperience.datareprez.DataReprezTools;
import eu.javaexperience.datareprez.convertFrom.DataReprezType;
import eu.javaexperience.datareprez.convertFrom.ModifiableObject;
import eu.javaexperience.datareprez.convertFrom.ObjectLike;
import eu.javaexperience.datareprez.jsonImpl.DataArrayJsonImpl;
import eu.javaexperience.reflect.CastTo;
import eu.javaexperience.reflect.Caster;
import eu.javaexperience.reflect.Mirror;
import eu.javaexperience.semantic.references.MayNotModified;
public class TargetObject implements ModifiableObject, ObjectLike
{
@Override
public DataReprezType getDataReprezType()
{
return DataReprezType.OBJECT;
}
@Override
public boolean has(String key)
{
return ArrayTools.contains(keys(), key);
}
protected static class ModifiableFields
{
public ModifiableFields(Class cls)
{
for(Field f:Mirror.collectClassFields(cls, true))
{
fields.put(f.getName(), f);
}
keys = fields.keySet().toArray(Mirror.emptyStringArray);
}
public String[] keys;
public Map<String, Field> fields = new HashMap<>();
}
protected static Map<Class, ModifiableFields> MF = new ConcurrentHashMap<>();
protected static ModifiableFields getMappingData(Class cls)
{
ModifiableFields ret = MF.get(cls);
if(null == ret)
{
ret = new ModifiableFields(cls);
MF.put(cls, ret);
}
return ret;
}
@Override
public String[] keys()
{
try
{
return getMappingData(getClass()).keys;
}
catch (Exception e)
{
Mirror.propagateAnyway(e);
return null;
}
}
@Override
public int size()
{
return keys().length;
}
@Override
public boolean set(String key, Object src)
{
return set(key, src, false);
}
@Override
public Object get(String key)
{
ModifiableFields mapping;
try
{
return getMappingData(getClass()).fields.get(key).get(this);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
public boolean set(String key, Object src, boolean filter)
{
try
{
ModifiableFields mapping = getMappingData(this.getClass());
Field f = mapping.fields.get(key);
if(null != f)
{
if(filter && null != f.getAnnotation(MayNotModified.class))
{
return false;
}
if(null != src)
{
src = tryCast(this, f.getGenericType(), src);
f.set(this, src);
}
}
}
catch(Exception e)
{
Mirror.propagateAnyway(e);
}
return false;
}
public static Type tryExtractGenericTypeOne(Type genRet)
{
if(genRet instanceof ParameterizedType)
{
Type[] args = ((ParameterizedType)genRet).getActualTypeArguments();
if(args.length > 0)
{
return args[0];
}
}
return null;
}
public static <T> Object tryCast(Object subject, Type reqType, Object src) throws Exception
{
Class<?> raw = Mirror.extracClass(reqType);
if(null != reqType && null != src && raw.isAssignableFrom(src.getClass()))
{
return src;
}
else if(raw.isEnum())
{
if(src instanceof DataObject)
{
return EnumTools.recogniseSymbol(raw, ((DataObject) src).optString("name"));
}
return EnumTools.recogniseSymbol(raw, src);
}
else if(Collection.class.isAssignableFrom(raw))
{
Collection ret = null;
Type generic = tryExtractGenericTypeOne(reqType);
if(!Modifier.isAbstract(raw.getModifiers()) && !raw.isInterface())
{
try
{
ret = (Collection) raw.newInstance();
}
catch(Exception e)
{}
}
if(null == ret)
{
if(Set.class.isAssignableFrom(raw))
{
ret = new HashSet<>();
}
else if(List.class.isAssignableFrom(raw))
{
ret = new ArrayList<>();
}
}
if(null == ret)
{
return null;
}
DataArray arr = null;
if(src instanceof String)
{
arr = new DataArrayJsonImpl(new JSONArray(src.toString()));
}
else if(src instanceof DataArray)
{
arr = (DataArray) src;
}
if(null == arr)
{
return null;
}
for(int i=0;i<arr.size();++i)
{
if(null != generic)
{
ret.add((T) tryCast(subject, generic, arr.get(i)));
}
else
{
ret.add(arr.get(i));
}
}
return ret;
}
else if(raw.isArray())
{
DataArray arr = null;
if(src instanceof String)
{
arr = new DataArrayJsonImpl(new JSONArray(src.toString()));
}
else if(src instanceof DataArray)
{
arr = (DataArray) src;
}
Class nType = raw.getComponentType();
T[] ret = (T[]) Array.newInstance(nType, arr.size());
for(int i=0;i<ret.length;++i)
{
ret[i] = (T) tryCast(subject, nType, arr.get(i));
}
return ret;
}
else if(String.class == reqType && src instanceof DataCommon)
{
byte[] ret = ((DataCommon)src).toBlob();
return null == ret?null:new String(ret);
}
else if(ModifiableObject.class.isAssignableFrom(raw) && src instanceof DataObject)
{
ModifiableObject ret = null;
if(!Modifier.isAbstract(raw.getModifiers()) && !raw.isInterface())
{
try
{
ret = (ModifiableObject) raw.newInstance();
}
catch(Exception e)
{}
}
if(null == ret)
{
ret = new TargetObject();
}
DataObject from = (DataObject) src;
DataReprezTools.copyInto(ret, from);
return ret;
}
Caster c = CastTo.getCasterRestrictlyForTargetClass(raw);
if(null != c)
{
return c.cast(src);
}
return null;
}
@Override
public void unset(String key)
{
set(key, null);
}
public void loadFrom(ObjectLike from)
{
for(String k:from.keys())
{
set(k, from.get(k));
}
}
public void loadFromUser(ObjectLike from)
{
for(String k:from.keys())
{
set(k, from.get(k), true);
}
}
@Override
public String toString()
{
return Mirror.usualToString(this);
}
}