WellKnownDataAccessors.java
package eu.javaexperience.reflect.property;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import eu.javaexperience.interfaces.IndexedStorage;
import eu.javaexperience.interfaces.ObjectWithProperty;
import eu.javaexperience.parse.ParsePrimitive;
import eu.javaexperience.reflect.Mirror;
public enum WellKnownDataAccessors implements DataAccessor
{
MAP()
{
@Override
public boolean canHandle(Object subject)
{
return subject instanceof Map;
}
@Override
public Object get(Object subject, String key)
{
return ((Map) subject).get(key);
}
@Override
public String[] keys(Object subject)
{
return ((Map<String,?> ) subject).keySet()
.toArray(Mirror.emptyStringArray);
}
},
ARRAY()
{
@Override
public boolean canHandle(Object subject)
{
return subject.getClass().isArray();
}
@Override
public Object get(Object subject, String key)
{
if(null == key)
{
return null;
}
int len = Array.getLength(subject);
if("length".equals(key))
{
return len;
}
if(0 == len)
{
return null;
}
if("first".equals(key))
{
return Array.get(subject, 0);
}
if("last".equals(key))
{
return Array.get(subject, len-1);
}
int index = ParsePrimitive.tryParseInt(key, -1);
if(-1 < index && index < len)
{
return Array.get(subject, index);
}
return null;
}
@Override
public String[] keys(Object subject)
{
return generateArrayKeys(Array.getLength(subject), true);
}
},
LIST()
{
@Override
public boolean canHandle(Object subject)
{
return subject instanceof List;
}
@Override
public Object get(Object subject, String key)
{
List s = (List) subject;
int len = s.size();
if("length".equals(key))
{
return len;
}
if(0 == len)
{
return null;
}
if("first".equals(key))
{
return s.get(0);
}
if("last".equals(key))
{
return s.get(len-1);
}
int index = ParsePrimitive.tryParseInt(key, -1);
if(-1 < index && index < len)
{
return s.get(index);
}
return null;
}
@Override
public String[] keys(Object subject)
{
return generateArrayKeys(((List) subject).size(), true);
}
},
OBJECT_PUBLIC_FIELDS()
{
@Override
public boolean canHandle(Object subject)
{
//always can access even if class has no public field
return true;
}
@Override
public Object get(Object subject, String key)
{
Map<String, Field> acc = getAccessorOfClass(subject.getClass());
Field f = acc.get(key);
if(null != f)
{
try
{
return f.get(subject);
}
catch (Exception e)
{
Mirror.propagateAnyway(e);
}
}
return null;
}
@Override
public String[] keys(Object subject)
{
Map<String, Field> acc = getAccessorOfClass(subject.getClass());
return acc.keySet().toArray(Mirror.emptyStringArray);
}
},
ARRAY_SIMPLEST()
{
@Override
public boolean canHandle(Object subject)
{
return subject.getClass().isArray();
}
@Override
public Object get(Object subject, String key)
{
if(null == key)
{
return null;
}
int len = Array.getLength(subject);
int index = ParsePrimitive.tryParseInt(key, -1);
if(-1 < index && index < len)
{
return Array.get(subject, index);
}
return null;
}
@Override
public String[] keys(Object subject)
{
return generateArrayKeys(Array.getLength(subject), false);
}
},
LIST_SIMPLEST()
{
@Override
public boolean canHandle(Object subject)
{
return subject instanceof List;
}
@Override
public Object get(Object subject, String key)
{
List s = (List) subject;
int len = s.size();
int index = ParsePrimitive.tryParseInt(key, -1);
if(-1 < index && index < len)
{
return s.get(index);
}
return null;
}
@Override
public String[] keys(Object subject)
{
return generateArrayKeys(((List) subject).size(), false);
}
},
OBJECT_LIKE()
{
@Override
public boolean canHandle(Object subject)
{
return subject instanceof ObjectWithProperty;
}
@Override
public Object get(Object subject, String key)
{
return ((ObjectWithProperty) subject).get(key);
}
@Override
public String[] keys(Object subject)
{
return ((ObjectWithProperty) subject).keys();
}
},
ARRAY_LIKE()
{
@Override
public boolean canHandle(Object subject)
{
return subject instanceof IndexedStorage;
}
@Override
public Object get(Object subject, String key)
{
return ((IndexedStorage) subject).get(Integer.parseInt(key));
}
@Override
public String[] keys(Object subject)
{
return generateArrayKeys(((IndexedStorage) subject).size(), false);
}
},
;
protected static ConcurrentMap<Class, Map<String,Field>>
classAccessors = new ConcurrentHashMap<Class, Map<String,Field>>();
public static Map<String, Field> getAccessorOfClass(Class cls)
{
Map<String, Field> ret = classAccessors.get(cls);
if(null == ret)
{
Field[] fs = Mirror.collectClassFields(cls, true);
ret = new HashMap<>();
for (Field f : fs)
{
f.setAccessible(true);
ret.put(f.getName(), f);
}
ret = Collections.unmodifiableMap(ret);
Map<String, Field> in = classAccessors.put(cls, ret);
if(null != in)
{
ret = in;
}
}
return ret;
}
protected static String[] generateArrayKeys(int len, boolean withExtra)
{
if(0 == len)
{
return Mirror.emptyStringArray;
}
String[] ret = new String[len+(withExtra?3:0)];
for(int i=0;i<len;++i)
{
ret[i] = String.valueOf(i);
}
if(withExtra)
{
ret[len] = "first";
ret[len+1] = "last";
ret[len+2] = "length";
}
return ret;
}
}