package net.minidev.asm;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public abstract class BeansAccess<T> {
private HashMap<String, Accessor> map;
private Accessor[] accs;
protected void setAccessor(Accessor[] accs) {
int i = 0;
this.accs = accs;
map = new HashMap<String, Accessor>();
for (Accessor acc : accs) {
acc.index = i++;
map.put(acc.getName(), acc);
}
}
public HashMap<String, Accessor> getMap() {
return map;
}
public Accessor[] getAccessors() {
return accs;
}
private static ConcurrentHashMap<Class<?>, BeansAccess<?>> cache = new ConcurrentHashMap<Class<?>, BeansAccess<?>>();
static public <P> BeansAccess<P> get(Class<P> type) {
return get(type, null);
}
static public <P> BeansAccess<P> get(Class<P> type, FieldFilter filter) {
{
@SuppressWarnings("unchecked")
BeansAccess<P> access = (BeansAccess<P>) cache.get(type);
if (access != null)
return access;
}
Accessor[] accs = ASMUtil.getAccessors(type, filter);
String className = type.getName();
String accessClassName;
if (className.startsWith("java.util."))
accessClassName = "net.minidev.asm." + className + "AccAccess";
else
accessClassName = className.concat("AccAccess");
DynamicClassLoader loader = new DynamicClassLoader(type.getClassLoader());
Class<?> accessClass = null;
try {
accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored) {
}
LinkedList<Class<?>> parentClasses = getParents(type);
if (accessClass == null) {
BeansAccessBuilder builder = new BeansAccessBuilder(type, accs, loader);
for (Class<?> c : parentClasses)
builder.addConversion(BeansAccessConfig.classMapper.get(c));
accessClass = builder.bulid();
}
try {
@SuppressWarnings("unchecked")
BeansAccess<P> access = (BeansAccess<P>) accessClass.newInstance();
access.setAccessor(accs);
cache.putIfAbsent(type, access);
for (Class<?> c : parentClasses)
addAlias(access, BeansAccessConfig.classFiledNameMapper.get(c));
return access;
} catch (Exception ex) {
throw new RuntimeException("Error constructing accessor class: " + accessClassName, ex);
}
}
private static LinkedList<Class<?>> getParents(Class<?> type) {
LinkedList<Class<?>> m = new LinkedList<Class<?>>();
while (type != null && !type.equals(Object.class)) {
m.addLast(type);
for (Class<?> c : type.getInterfaces())
m.addLast(c);
type = type.getSuperclass();
}
m.addLast(Object.class);
return m;
}
private static void addAlias(BeansAccess<?> access, HashMap<String, String> m) {
if (m == null)
return;
HashMap<String, Accessor> changes = new HashMap<String, Accessor>();
for (Entry<String, String> e : m.entrySet()) {
Accessor a1 = access.map.get(e.getValue());
if (a1 != null)
changes.put(e.getValue(), a1);
}
access.map.putAll(changes);
}
abstract public void set(T object, int methodIndex, Object value);
abstract public Object get(T object, int methodIndex);
abstract public T newInstance();
public void set(T object, String methodName, Object value) {
int i = getIndex(methodName);
if (i == -1)
throw new net.minidev.asm.ex.NoSuchFieldException(methodName + " in " + object.getClass() + " to put value : " + value);
set(object, i, value);
}
public Object get(T object, String methodName) {
return get(object, getIndex(methodName));
}
public int getIndex(String name) {
Accessor ac = map.get(name);
if (ac == null)
return -1;
return ac.index;
}
}