net.minidev.asm.BeansAccess Maven / Gradle / Ivy
Show all versions of accessors-smart Show documentation
package net.minidev.asm;
/*
* Copyright 2011-2023 JSON-SMART authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
* Allow access reflect field using runtime generated accessor. BeansAccessor is
* faster than java.lang.reflect.Method.invoke()
*
* @param the type of the bean being accessed
* @author uriel Chemouni
*/
public abstract class BeansAccess {
/**
* default constuctor
*/
public BeansAccess() {
super();
}
private HashMap map;
private Accessor[] accs;
/**
* set Accessor
* @param accs Accessor list
*/
protected void setAccessor(Accessor[] accs) {
int i = 0;
this.accs = accs;
map = new HashMap();
for (Accessor acc : accs) {
acc.index = i++;
map.put(acc.getName(), acc);
}
}
/**
* get internal map
* @return a map
*/
public HashMap getMap() {
return map;
}
/**
* get internal accessor
* @return Accessor list
*/
public Accessor[] getAccessors() {
return accs;
}
/**
* cache used to store built BeansAccess
*/
private static ConcurrentHashMap, BeansAccess>> cache = new ConcurrentHashMap, BeansAccess>>();
// private final static ConcurrentHashMap> cache;
/**
* return the BeansAccess corresponding to a type
*
* @param type to be access
* @param working type
* @return the BeansAccess
*/
static public
BeansAccess
get(Class
type) {
return get(type, null);
}
/**
* return the BeansAccess corresponding to a type
*
* @param filter FieldFilter
* @param type to be access
* @param
working type
* @return the BeansAccess
*/
static public
BeansAccess
get(Class
type, FieldFilter filter) {
{
@SuppressWarnings("unchecked")
BeansAccess
access = (BeansAccess
) cache.get(type);
if (access != null)
return access;
}
// extract all access methods
Accessor[] accs = ASMUtil.getAccessors(type, filter);
// create new class name
String className = type.getName();
String accessClassName;
if (className.startsWith("java.util."))
accessClassName = "net.minidev.asm." + className + "AccAccess";
else
accessClassName = className.concat("AccAccess");
// extend class base loader
DynamicClassLoader loader = new DynamicClassLoader(type.getClassLoader());
// try to load existing class
Class> accessClass = null;
try {
accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored) {
}
LinkedList> parentClasses = getParents(type);
// if the class do not exists build it
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 access = (BeansAccess
) accessClass.newInstance();
access.setAccessor(accs);
cache.putIfAbsent(type, access);
// add fieldname alias
for (Class> c : parentClasses)
addAlias(access, BeansAccessConfig.classFiledNameMapper.get(c));
return access;
} catch (Exception ex) {
throw new RuntimeException("Error constructing accessor class: " + accessClassName, ex);
}
}
/**
* @param type current type
* @return parents hierarchy
*/
private static LinkedList> getParents(Class> type) {
LinkedList> m = new LinkedList>();
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;
}
/**
* @param access accessor to use
* @param m mapping
*/
private static void addAlias(BeansAccess> access, HashMap m) {
// HashMap m =
// BeansAccessConfig.classFiledNameMapper.get(type);
if (m == null)
return;
HashMap changes = new HashMap();
for (Entry e : m.entrySet()) {
Accessor a1 = access.map.get(e.getValue());
if (a1 != null)
changes.put(e.getValue(), a1);
}
access.map.putAll(changes);
}
/**
* set field value by field index
*
* @param object object to alter
* @param methodIndex field id to update
* @param value new value
*/
abstract public void set(T object, int methodIndex, Object value);
/**
* get field value by field index
* @param object object to operate
* @param methodIndex field number to operate
* @return value of the field
*/
abstract public Object get(T object, int methodIndex);
/**
* create a new targeted object
* @return new instance
*/
abstract public T newInstance();
/**
* set field value by field name
* @param object target object
* @param methodName methodName
* @param value new field value
*/
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);
}
/**
* get field value by field name
* @param object object to operate
* @param methodName getter to call
* @return field value returned by the getter
*/
public Object get(T object, String methodName) {
return get(object, getIndex(methodName));
}
/**
* Returns the index of the field accessor.
* @param name field name
* @return id of the field
*/
public int getIndex(String name) {
Accessor ac = map.get(name);
if (ac == null)
return -1;
return ac.index;
}
}