package net.minidev.asm;

/*
 *    Copyright 2011 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()
Author:uriel Chemouni
/** * Allow access reflect field using runtime generated accessor. BeansAccessor is * faster than java.lang.reflect.Method.invoke() * * @author uriel Chemouni */
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; }
cache used to store built BeansAccess
/** * cache used to store built BeansAccess */
private static ConcurrentHashMap<Class<?>, BeansAccess<?>> cache = new ConcurrentHashMap<Class<?>, BeansAccess<?>>(); // private final static ConcurrentHashMap<Type, AMapper<?>> cache;
return the BeansAccess corresponding to a type
Params:
  • type – to be access
Returns:the BeansAccess
/** * return the BeansAccess corresponding to a type * * @param type * to be access * @return the BeansAccess */
static public <P> BeansAccess<P> get(Class<P> type) { return get(type, null); }
return the BeansAccess corresponding to a type
Params:
  • type – to be access
Returns:the BeansAccess
/** * return the BeansAccess corresponding to a type * * @param type * to be access * @return the BeansAccess */
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; } // extract all access methodes 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<Class<?>> 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<P> access = (BeansAccess<P>) 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); } } 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) { // HashMap<String, String> m = // BeansAccessConfig.classFiledNameMapper.get(type); 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); }
set field value by field index
/** * set field value by field index */
abstract public void set(T object, int methodIndex, Object value);
get field value by field index
/** * get field value by field index */
abstract public Object get(T object, int methodIndex);
create a new targeted object
/** * create a new targeted object */
abstract public T newInstance();
set field value by fieldname
/** * set field value by fieldname */
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 fieldname
/** * get field value by fieldname */
public Object get(T object, String methodName) { return get(object, getIndex(methodName)); }
Returns the index of the field accessor.
/** * Returns the index of the field accessor. */
public int getIndex(String name) { Accessor ac = map.get(name); if (ac == null) return -1; return ac.index; } }