org.macrocloud.kernel.toolkit.beans.BeanMapEmitter Maven / Gradle / Ivy
package org.macrocloud.kernel.toolkit.beans;
import org.macrocloud.kernel.toolkit.utils.ReflectUtil;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.Type;
import org.springframework.cglib.core.*;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 重写 cglib BeanMap 处理器.
*
* @author macro
*/
class BeanMapEmitter extends ClassEmitter {
/** The Constant BEAN_MAP. */
private static final Type BEAN_MAP = TypeUtils.parseType(BaseBeanMap.class.getName());
/** The Constant FIXED_KEY_SET. */
private static final Type FIXED_KEY_SET = TypeUtils.parseType("org.springframework.cglib.beans.FixedKeySet");
/** The Constant CSTRUCT_OBJECT. */
private static final Signature CSTRUCT_OBJECT = TypeUtils.parseConstructor("Object");
/** The Constant CSTRUCT_STRING_ARRAY. */
private static final Signature CSTRUCT_STRING_ARRAY = TypeUtils.parseConstructor("String[]");
/** The Constant BEAN_MAP_GET. */
private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object, Object)");
/** The Constant BEAN_MAP_PUT. */
private static final Signature BEAN_MAP_PUT = TypeUtils.parseSignature("Object put(Object, Object, Object)");
/** The Constant KEY_SET. */
private static final Signature KEY_SET = TypeUtils.parseSignature("java.util.Set keySet()");
/** The Constant NEW_INSTANCE. */
private static final Signature NEW_INSTANCE = new Signature("newInstance", BEAN_MAP, new Type[]{Constants.TYPE_OBJECT});
/** The Constant GET_PROPERTY_TYPE. */
private static final Signature GET_PROPERTY_TYPE = TypeUtils.parseSignature("Class getPropertyType(String)");
/**
* Instantiates a new bean map emitter.
*
* @param v the v
* @param className the class name
* @param type the type
* @param require the require
*/
public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) {
super(v);
begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
EmitUtils.null_constructor(this);
EmitUtils.factory_method(this, NEW_INSTANCE);
generateConstructor();
Map getters = makePropertyMap(ReflectUtil.getBeanGetters(type));
Map setters = makePropertyMap(ReflectUtil.getBeanSetters(type));
Map allProps = new HashMap<>(32);
allProps.putAll(getters);
allProps.putAll(setters);
if (require != 0) {
for (Iterator it = allProps.keySet().iterator(); it.hasNext(); ) {
String name = (String) it.next();
if ((((require & BaseBeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
(((require & BaseBeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) {
it.remove();
getters.remove(name);
setters.remove(name);
}
}
}
generateGet(type, getters);
generatePut(type, setters);
String[] allNames = getNames(allProps);
generateKeySet(allNames);
generateGetPropertyType(allProps, allNames);
end_class();
}
/**
* Make property map.
*
* @param props the props
* @return Map the map
*/
private Map makePropertyMap(PropertyDescriptor[] props) {
Map names = new HashMap<>(16);
for (PropertyDescriptor prop : props) {
String propName = prop.getName();
// 过滤 getClass,Spring 的工具类会拿到该方法
if (!"class".equals(propName)) {
names.put(propName, prop);
}
}
return names;
}
/**
* Gets the names.
*
* @param propertyMap the property map
* @return String[] the names
*/
private String[] getNames(Map propertyMap) {
return propertyMap.keySet().toArray(new String[0]);
}
/**
* Generate constructor.
*/
private void generateConstructor() {
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
e.load_this();
e.load_arg(0);
e.super_invoke_constructor(CSTRUCT_OBJECT);
e.return_value();
e.end_method();
}
/**
* Generate get.
*
* @param type the type
* @param getters the getters
*/
private void generateGet(Class type, final Map getters) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null);
e.load_arg(0);
e.checkcast(Type.getType(type));
e.load_arg(1);
e.checkcast(Constants.TYPE_STRING);
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
@Override
public void processCase(Object key, Label end) {
PropertyDescriptor pd = getters.get(key);
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
e.invoke(method);
e.box(method.getSignature().getReturnType());
e.return_value();
}
@Override
public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
}
/**
* Generate put.
*
* @param type the type
* @param setters the setters
*/
private void generatePut(Class type, final Map setters) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null);
e.load_arg(0);
e.checkcast(Type.getType(type));
e.load_arg(1);
e.checkcast(Constants.TYPE_STRING);
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
@Override
public void processCase(Object key, Label end) {
PropertyDescriptor pd = setters.get(key);
if (pd.getReadMethod() == null) {
e.aconst_null();
} else {
MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod());
e.dup();
e.invoke(read);
e.box(read.getSignature().getReturnType());
}
// move old value behind bean
e.swap();
// new value
e.load_arg(2);
MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod());
e.unbox(write.getSignature().getArgumentTypes()[0]);
e.invoke(write);
e.return_value();
}
@Override
public void processDefault() {
// fall-through
}
});
e.aconst_null();
e.return_value();
e.end_method();
}
/**
* Generate key set.
*
* @param allNames the all names
*/
private void generateKeySet(String[] allNames) {
// static initializer
declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null);
CodeEmitter e = begin_static();
e.new_instance(FIXED_KEY_SET);
e.dup();
EmitUtils.push_array(e, allNames);
e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
e.putfield("keys");
e.return_value();
e.end_method();
// keySet
e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null);
e.load_this();
e.getfield("keys");
e.return_value();
e.end_method();
}
/**
* Generate get property type.
*
* @param allProps the all props
* @param allNames the all names
*/
private void generateGetPropertyType(final Map allProps, String[] allNames) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null);
e.load_arg(0);
EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
@Override
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor) allProps.get(key);
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
e.return_value();
}
@Override
public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy