package com.zhouyy.netBank.util; import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils; import com.zhouyy.netBank.framework.cglib.beans.BeanCopier;
import com.zhouyy.netBank.framework.cglib.beans.BeanMap; /**
* Bean转换工具
*
* @author zhouyy
* @version 0.0.5
*/
public abstract class BeanUtils extends org.springframework.beans.BeanUtils { private static final Map<String, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();
private static final Map<String, BeanCopier> NONE_NULL_BEAN_COPIER_MAP = new ConcurrentHashMap<>(); /**
* MAP集合转成bean对象集合
*
* @param listResult 需要拷贝的集合
* @param clazz 需要将map转换成的Class
* @param <B> 泛型
* @return 集合泛型
* @author zhouyy
*/
public static <B> List<B> copyMapListProperties(List listResult, Class<B> clazz) {
List<B> sourceList = new ArrayList<>();
Map<String, Object> cacheMap = new HashMap<>();
//遍历MAP结果集
for (Object obj : listResult) {
Map map = (Map) obj;
B source = copyMapProperties(map, clazz, cacheMap);
// if (null != clazz) {
// source = copyMapProperties(map, clazz, cacheMap);
// } else {
// Map<String, Object> newMap = new HashMap<>();
// Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator();
// while (entries.hasNext()) {
// Map.Entry<String, Object> entry = entries.next();
// newMap.put(entry.getKey().toLowerCase(), entry.getValue());
// }
// source = (B) newMap;
// }
sourceList.add(source);
}
return sourceList;
} /**
* MAP转成bean对象集合
*
* @param map
* @param clazz
* @param <B>
* @return
* @author zhouyy
*/
public static <B> B copyMapProperties(Map map, Class<B> clazz) {
Map<String, Object> cacheMap = new HashMap<>();
return copyMapProperties(map, clazz, cacheMap);
} /**
* 递归获取当前class的所有父类中的属性
*
* @param clazz 需要获取的类
* @param fieldList 字段集合
*/
public static void getAllFields(Class<?> clazz, List<Field> fieldList) {
Class superClass = clazz.getSuperclass();
if (superClass != Object.class) {
getAllFields(superClass, fieldList);
}
Field[] fields = clazz.getDeclaredFields();
fieldList.addAll(Arrays.asList(fields));
} /**
* MAP转成bean对象集合
*
* @param map
* @param clazz
* @param cacheMap
* @param <B>
* @return
* @author zhouyy
*/
@SuppressWarnings("unchecked")
private static <B> B copyMapProperties(Map map, Class<B> clazz, Map<String, Object> cacheMap) {
Assert.notNull(map, "map must not be null");
Assert.notNull(clazz, "clazz must not be null"); B instantiate = instantiate(clazz);
BeanMap beanMap = BeanMap.create(instantiate, true);
beanMap.putAll(map);
return instantiate; // List<Field> fieldList = (List<Field>) cacheMap.get(clazz);
// if (fieldList == null) {
// fieldList = new ArrayList<>();
// getAllFields(clazz, fieldList);
// }
//
// B source = null;
// try {
// source = clazz.newInstance();
// } catch (InstantiationException | IllegalAccessException e) {
// e.printStackTrace();
// }
// //遍历结果MAP
// Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
// while (it.hasNext()) {
// Map.Entry<String, Object> entry = it.next();
// //遍历映射实体属性
// for (Field field : fieldList) {
// String key = entry.getKey();
// Boolean flag = (Boolean) cacheMap.get(key + field.getName());
// if (flag == null) {
// flag = !key.replace("_", "").equalsIgnoreCase(field.getName());
// cacheMap.put(key + field.getName(), flag);
// }
// if (flag) {
// continue;
// }
//
// Object value = entry.getValue();
// Class typeClass = field.getType();
// Object valueType = setFieldValueByFieldType(value, typeClass);
// ReflectionUtils.makeAccessible(field);
// ReflectionUtils.setField(field, source, valueType);
// }
// }
// return source;
} // private static Object setFieldValueByFieldType(Object value, Class typeClass) {
// //这里去掉typeClass == double.class是为了代码规范,保证bean中的属性使用包装类
// if ((value instanceof Character) && typeClass == String.class) {
// Character character = (Character) value;
// value = character.toString();
// }else if(value instanceof Number){
// Number number = (Number) value;
// if (typeClass == BigDecimal.class) {
// value = BigDecimal.valueOf(number.doubleValue());
// } else if (typeClass == BigInteger.class) {
// value = BigInteger.valueOf(number.longValue());
// } else if (typeClass == Long.class) {
// value = number.longValue();
// } else if (typeClass == Integer.class) {
// value = number.intValue();
// } else if (typeClass == Double.class) {
// value = number.doubleValue();
// } else if (typeClass == Float.class) {
// value = number.floatValue();
// } else if (typeClass == Short.class) {
// value = number.shortValue();
// } else if (typeClass == Byte.class) {
// value = number.byteValue();
// } else {
// value = number;
// }
// }
// return value;
// }
private static String getBeanCopierCacheKey(Class source, Class target) {
return source.getName() + "|" + target.getName();
} private static BeanCopier getBeanCopier(Class source, Class target) {
String beanCopierCacheKey = getBeanCopierCacheKey(source, target);
BeanCopier beanCopier = BEAN_COPIER_MAP.get(beanCopierCacheKey);
if (beanCopier == null) {
beanCopier = BeanCopier.create(source, target, false);
BEAN_COPIER_MAP.put(beanCopierCacheKey, beanCopier);
}
return beanCopier;
} private static BeanCopier getNoneNullBeanCopier(Class source, Class target) {
String beanCopierCacheKey = getBeanCopierCacheKey(source, target);
BeanCopier beanCopier = NONE_NULL_BEAN_COPIER_MAP.get(getBeanCopierCacheKey(source, target));
if (beanCopier == null) {
beanCopier = BeanCopier.create(source, target, false, true);
NONE_NULL_BEAN_COPIER_MAP.put(beanCopierCacheKey, beanCopier);
}
return beanCopier;
} /**
* 作者:zhouyy
* 批量转换List<Bean>
*
* @param source list集合
* @param t 所成对象的class
* @param <B>
* @return List<T>
* @throws BeansException
*/
public static <S, B> List<B> copyListProperties(List<S> source, Class<B> t) throws BeansException {
List<B> list = new ArrayList<>();
if (CollectionUtils.isEmpty(source)) {
return list;
} BeanCopier beanCopier = getBeanCopier(source.get(0).getClass(), t);
for (Object o : source) {
B instantiate = instantiate(t);
beanCopier.copy(o, instantiate, null);
// copyProperties(o, instantiate);
list.add(instantiate);
}
return list;
// List<B> list = new ArrayList<>();
// if (source == null) {
// return list;
// }
// try {
// for (Object o : source) {
// B tObj = t.newInstance();
// copyProperties(o, tObj);
// list.add(tObj);
// }
// } catch (InstantiationException | IllegalAccessException e) {
// e.printStackTrace();
// }
// return list;
} public static Map<String, Object> beanToMap(Object obj) {
BeanMap beanMap = BeanMap.create(obj);
HashMap<String, Object> copy = new HashMap<>();
for (Object key : beanMap.keySet()) {
copy.put((String) key, beanMap.get(key));
}
return copy;
// if (obj == null) {
// return null;
// }
// Map<String, Object> map = new HashMap<>();
// try {
// BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
// PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
// for (PropertyDescriptor property : propertyDescriptors) {
// String key = property.getName();
// // 过滤class属性
// if (!key.equals("class")) {
// // 得到property对应的getter方法
// Method getter = property.getReadMethod();
// Object value = getter.invoke(obj);
//
// map.put(key, value);
// }
// }
// } catch (Exception e) {
// logger.error("transBean2Map Error {}", e);
// }
// return map;
} /**
* 将两个对象集合合并,并且转换为Map集合
*
* @param listA 对象集合A
* @param listB 对象集合B
* @param key 根据对象中的哪个值进行合并
* @return 合并后的Map集合
*/
public static List<Map<String, Object>> mergeListBeanToMap(List<?> listA, List<?> listB, String key) {
List<Map<String, Object>> list = new ArrayList<>();
for (Object objA : listA) {
//将对象转换为Map
Map<String, Object> mapA = beanToMap(objA);
for (Object objB : listB) {
//将对象转换为Map
Map<String, Object> mapB = beanToMap(objB);
//如果对象A和对象B的值一直,则合并两个对象Map
if (mapA.get(key).equals(mapB.get(key))) {
mapA.putAll(mapB);
}
}
//如果集合中不存在Map,则往List中追加合并后的Map
if (!list.contains(mapA)) {
list.add(mapA);
}
}
return list;
} /**
* 将两个对象转换为map并做合并 *** 作
*
* @param objA 对象A
* @param objB 对象B
* @param key 根据什么属性合并,属性名
* @return 合并后的Map
*/
public static Map<String, Object> mergeBeanToMap(Object objA, Object objB, String key) {
if (objA == null) {
return null;
}
Map<String, Object> mapA = beanToMap(objA);
if (objB == null) {
return mapA;
}
Map<String, Object> mapB = beanToMap(objB);
if (mapA.get(key).equals(mapB.get(key))) {
mapA.putAll(mapB);
}
return mapA;
} /**
* 把source和target相同属性的value复制到target中
*
* @param source 准备赋值对象
* @param target 被赋值对象
* @throws BeansException
*/
public static void copyNotNullProperties(Object source, Object target) throws BeansException {
BeanCopier noneNullBeanCopier = getNoneNullBeanCopier(source.getClass(), target.getClass());
noneNullBeanCopier.copy(source, target, null);
// copyProperties(source, target, null, null);
} public static void copyNotNullProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
copyProperties(source, target, null, ignoreProperties);
} public static <B> B copyNewInstanceProperties(Object source, Class<B> t) throws BeansException {
BeanCopier beanCopier = getBeanCopier(source.getClass(), t);
B instantiate = instantiate(t);
beanCopier.copy(source, instantiate, null);
return instantiate;
// B tObj = null;
// try {
// tObj = t.newInstance();
// } catch (InstantiationException | IllegalAccessException e) {
// logger.error("copyNewInstanceProperties Error {}", e);
// }
// copyProperties(source, tObj);
// return tObj;
} private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException { Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null"); Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
"] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null &&
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (value != null) { //只拷贝不为null的属性
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
} catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package com.zhouyy.netBank.framework.cglib.beans; 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.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map; public abstract class BeanCopier {
private static final BeanCopier.BeanCopierKey KEY_FACTORY = (BeanCopier.BeanCopierKey) KeyFactory.create(BeanCopier.BeanCopierKey.class);
private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter");
private static final Type BEAN_COPIER = TypeUtils.parseType(BeanCopier.class.getName());
private static final Signature COPY;
private static final Signature CONVERT; public BeanCopier() {
} public static BeanCopier create(Class source, Class target, boolean useConverter) {
BeanCopier.Generator gen = new BeanCopier.Generator();
gen.setSource(source);
gen.setTarget(target);
gen.setUseConverter(useConverter);
return gen.create();
} public static BeanCopier create(Class source, Class target, boolean useConverter, boolean useNoneNull) {
BeanCopier.Generator gen = new BeanCopier.Generator();
gen.setSource(source);
gen.setTarget(target);
gen.setUseConverter(useConverter);
gen.setUseNoneNull(useNoneNull);
return gen.create();
} public abstract void copy(Object var1, Object var2, Converter var3); static {
COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER});
CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)");
} public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanCopier.class.getName());
private Class source;
private Class target;
//使用转换器
private boolean useConverter;
//使用非空判断
private boolean useNoneNull; public Generator() {
super(SOURCE);
} public void setSource(Class source) {
if (!Modifier.isPublic(source.getModifiers())) {
this.setNamePrefix(source.getName());
} this.source = source;
} public void setTarget(Class target) {
if (!Modifier.isPublic(target.getModifiers())) {
this.setNamePrefix(target.getName());
} this.target = target;
} public void setUseNoneNull(boolean useNoneNull) {
this.useNoneNull = useNoneNull;
} public void setUseConverter(boolean useConverter) {
this.useConverter = useConverter;
} protected ClassLoader getDefaultClassLoader() {
return this.source.getClassLoader();
} protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(this.source);
} public BeanCopier create() {
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter,this.useNoneNull);
return (BeanCopier)super.create(key);
} public void generateClass(ClassVisitor v) {
Type sourceType = Type.getType(source);
Type targetType = Type.getType(target);
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_7, Constants.ACC_PUBLIC, getClassName(), BEAN_COPIER, null, Constants.SOURCE_FILE); EmitUtils.null_constructor(ce);
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
Map<Object, Object> names = new HashMap<>(); for (int i = 0; i < getters.length; ++i) {
names.put(getters[i].getName(), getters[i]);
} Local targetLocal = e.make_local();
Local sourceLocal = e.make_local();
if (this.useConverter) {
e.load_arg(1);
e.checkcast(targetType);
e.store_local(targetLocal);
e.load_arg(0);
e.checkcast(sourceType);
e.store_local(sourceLocal);
} else {
e.load_arg(1);
e.checkcast(targetType);
e.load_arg(0);
e.checkcast(sourceType);
} for (int i = 0; i < setters.length; ++i) {
PropertyDescriptor setter = setters[i];
PropertyDescriptor getter = (PropertyDescriptor) names.get(setter.getName());
if (getter != null) {
Class<?> returnType = getter.getReadMethod().getReturnType();
//是否为基本数据类型 true是,false否
boolean isPrimitive = returnType.isPrimitive();
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
Type setterType = write.getSignature().getArgumentTypes()[0];
if (this.useConverter) {
Label start = null;
if (this.useNoneNull && !isPrimitive) {
//将sourceLocal压入栈顶,以便在if处能获取到source对象的变量
e.load_local(sourceLocal);
//创建标签
start = e.make_label();
//调用getter方法,获取值
e.invoke(read);
//进行非空判断
e.ifnull(start);
}
e.load_local(targetLocal);
e.load_arg(2);
e.load_local(sourceLocal);
e.invoke(read);
e.box(read.getSignature().getReturnType());
EmitUtils.load_class(e, setterType);
e.push(write.getSignature().getName());
e.invoke_interface(BeanCopier.CONVERTER, BeanCopier.CONVERT);
e.unbox_or_zero(setterType);
e.invoke(write); if (start != null) {
//结束
e.mark(start);
}
} else if (compatible(getter, setter)) {
//如果是非空复制
Label start = null;
if (this.useNoneNull && !isPrimitive) {
//复制栈顶并进行压栈
e.dup();
//创建标签
start = e.make_label();
//调用getter方法,获取值
e.invoke(read);
//进行非空判断
e.ifnull(start);
}
e.dup2();
e.invoke(read);
e.invoke(write);
if (start != null) {
//结束
e.mark(start);
}
}
}
}
e.return_value();
e.end_method();
ce.end_class();
} private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
} protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type);
} protected Object nextInstance(Object instance) {
return instance;
}
} interface BeanCopierKey {
Object newInstance(String var1, String var2, boolean var3, boolean useNoneNull);
}
}
package com.zhouyy.netBank.framework.cglib.beans; import java.math.BigDecimal;
import java.math.BigInteger; /**
* 基础数据类型转换,在BeanMapEmitter使用cglib生成的代码中使用该类
*
* @author zhoul
* create time 2019-06-20
*/
public abstract class BasicDataCast { public static Object cast(Object source, Class target) {
if(source == null){
return null;
}
// 如果类型一致,则直接返回
if (source.getClass() == target) {
return source;
}
if (source instanceof Character) {
Character character = (Character) source;
if (target == String.class) {
return character.toString();
}
} else if (source instanceof CharSequence) {
CharSequence character = (CharSequence) source;
if (target == String.class) {
return character.toString();
}
} else if (source instanceof Number) {
Number number = (Number) source;
if (target == BigDecimal.class) {
return BigDecimal.valueOf(number.doubleValue());
} else if (target == BigInteger.class) {
return BigInteger.valueOf(number.longValue());
} else if (target == Long.class) {
return number.longValue();
} else if (target == Integer.class) {
return number.intValue();
} else if (target == Double.class) {
return number.doubleValue();
} else if (target == Float.class) {
return number.floatValue();
} else if (target == Short.class) {
return number.shortValue();
} else if (target == Byte.class) {
return number.byteValue();
}else if (target == String.class) {
return number.toString();
}
}
return source;
}
}
package com.zhouyy.netBank.framework.cglib.beans; import org.springframework.asm.ClassVisitor;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.KeyFactory;
import org.springframework.cglib.core.ReflectUtils; import java.security.ProtectionDomain;
import java.util.*; /**
* A <code>Map</code>-based view of a JavaBean. The default set of keys is the
* union of all property names (getters or setters). An attempt to set
* a read-only property will be ignored, and write-only properties will
* be returned as <code>null</code>. Removal of objects is not a
* supported (the key set is fixed).
*
* @author Chris Nokleberg
* @author zhoul
*/
abstract public class BeanMap implements Map {
/**
* Limit the properties reflected in the key set of the map
* to readable properties.
*
* @see BeanMap.Generator#setRequire
*/
public static final int REQUIRE_GETTER = 1; /**
* Limit the properties reflected in the key set of the map
* to writable properties.
*
* @see BeanMap.Generator#setRequire
*/
public static final int REQUIRE_SETTER = 2; /**
* Helper method to create a new <code>BeanMap</code>. For finer
* control over the generated instance, use a new instance of
* <code>BeanMap.Generator</code> instead of this static method.
*
* @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance
*/
public static BeanMap create(Object bean) {
Generator gen = new Generator();
gen.setBean(bean);
return gen.create();
} /**
* 创建对象
*
* @param bean
* @param ignoreKeyCase 是否忽略KEY的大小写,要与putAllIgnoreKeyCase配合使用
* @return
*/
public static BeanMap create(Object bean, boolean ignoreKeyCase) {
Generator gen = new Generator();
gen.setBean(bean);
gen.setIgnoreKeyCase(ignoreKeyCase);
return gen.create();
} public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanMap.class.getName()); private static final BeanMapKey KEY_FACTORY =
(BeanMapKey) KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); interface BeanMapKey {
public Object newInstance(Class type, int require, boolean ignoreKeyCase);
} private Object bean;
private Class beanClass;
private int require;
private boolean ignoreKeyCase; public Generator() {
super(SOURCE);
} public void setIgnoreKeyCase(boolean ignoreKeyCase) {
this.ignoreKeyCase = ignoreKeyCase;
} /**
* Set the bean that the generated map should reflect. The bean may be swapped
* out for another bean of the same type using {@link #setBean}.
* Calling this method overrides any value previously set using {@link #setBeanClass}.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
*
* @param bean the initial bean
*/
public void setBean(Object bean) {
this.bean = bean;
if (bean != null)
beanClass = bean.getClass();
} /**
* Set the class of the bean that the generated map should support.
* You must call either this method or {@link #setBeanClass} before {@link #create}.
*
* @param beanClass the class of the bean
*/
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
} /**
* Limit the properties reflected by the generated map.
*
* @param require any combination of {@link #REQUIRE_GETTER} and
* {@link #REQUIRE_SETTER}; default is zero (any property allowed)
*/
public void setRequire(int require) {
this.require = require;
} protected ClassLoader getDefaultClassLoader() {
return beanClass.getClassLoader();
} protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(beanClass);
} /**
* Create a new instance of the <code>BeanMap</code>. An existing
* generated class will be reused if possible.
*/
public BeanMap create() {
if (beanClass == null) {
throw new IllegalArgumentException("Class of bean unknown");
}
setNamePrefix(beanClass.getName());
return (BeanMap) super.create(KEY_FACTORY.newInstance(beanClass, require, ignoreKeyCase));
} public void generateClass(ClassVisitor v) throws Exception {
new BeanMapEmitter(v, getClassName(), beanClass, require, ignoreKeyCase);
} protected Object firstInstance(Class type) {
return ((BeanMap) ReflectUtils.newInstance(type)).newInstance(bean);
} protected Object nextInstance(Object instance) {
return ((BeanMap) instance).newInstance(bean);
}
} /**
* Create a new <code>BeanMap</code> instance using the specified bean.
* This is faster than using the {@link #create} static method.
*
* @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance
*/
abstract public BeanMap newInstance(Object bean); /**
* Get the type of a property.
*
* @param name the name of the JavaBean property
* @return the type of the property, or null if the property does not exist
*/
abstract public Class getPropertyType(String name); protected Object bean; protected BeanMap() {
} protected BeanMap(Object bean) {
setBean(bean);
} public Object get(Object key) {
return get(bean, key);
} public Object put(Object key, Object value) {
return put(bean, key, value);
} /**
* Get the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead.
*
* @param bean the bean to query; must be compatible with the type of
* this <code>BeanMap</code>
* @param key must be a String
* @return the current value, or null if there is no matching property
*/
abstract public Object get(Object bean, Object key); /**
* Set the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead.
*
* @param key must be a String
* @return the old value, if there was one, or null
*/
abstract public Object put(Object bean, Object key, Object value); /**
* Change the underlying bean this map should use.
*
* @param bean the new JavaBean
* @see #getBean
*/
public void setBean(Object bean) {
this.bean = bean;
} /**
* Return the bean currently in use by this map.
*
* @return the current JavaBean
* @see #setBean
*/
public Object getBean() {
return bean;
} public void clear() {
throw new UnsupportedOperationException();
} public boolean containsKey(Object key) {
return keySet().contains(key);
} public boolean containsValue(Object value) {
for (Iterator it = keySet().iterator(); it.hasNext(); ) {
Object v = get(it.next());
if (((value == null) && (v == null)) || (value != null && value.equals(v)))
return true;
}
return false;
} public int size() {
return keySet().size();
} public boolean isEmpty() {
return size() == 0;
} public Object remove(Object key) {
throw new UnsupportedOperationException();
} public void putAll(Map t) {
for (Iterator it = t.keySet().iterator(); it.hasNext(); ) {
Object key = it.next();
put(key, t.get(key));
}
} public boolean equals(Object o) {
if (o == null || !(o instanceof Map)) {
return false;
}
Map other = (Map) o;
if (size() != other.size()) {
return false;
}
for (Iterator it = keySet().iterator(); it.hasNext(); ) {
Object key = it.next();
if (!other.containsKey(key)) {
return false;
}
Object v1 = get(key);
Object v2 = other.get(key);
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
return false;
}
}
return true;
} public int hashCode() {
int code = 0;
for (Iterator it = keySet().iterator(); it.hasNext(); ) {
Object key = it.next();
Object value = get(key);
code += ((key == null) ? 0 : key.hashCode()) ^
((value == null) ? 0 : value.hashCode());
}
return code;
} // TODO: optimize
public Set entrySet() {
HashMap<Object, Object> copy = new HashMap<>();
for (Object key : keySet()) {
copy.put(key, get(key));
}
return Collections.unmodifiableMap(copy).entrySet();
} public Collection values() {
Set keys = keySet();
List<Object> values = new ArrayList<>(keys.size());
for (Object key : keys) {
values.add(get(key));
}
return Collections.unmodifiableCollection(values);
} /*
* @see java.util.AbstractMap#toString
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append('{');
for (Iterator it = keySet().iterator(); it.hasNext(); ) {
Object key = it.next();
sb.append(key);
sb.append('=');
sb.append(get(key));
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append('}');
return sb.toString();
}
}
package com.zhouyy.netBank.framework.cglib.beans; import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.Type;
import org.springframework.cglib.beans.FixedKeySet;
import org.springframework.cglib.core.*;
import org.springframework.util.StringUtils; import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map; class BeanMapEmitter extends ClassEmitter {
private static final Type BEAN_MAP = TypeUtils.parseType(BeanMap.class.getName());
private static final Type FIXED_KEY_SET = TypeUtils.parseType(FixedKeySet.class.getName());
private static final Signature CSTRUCT_OBJECT = TypeUtils.parseConstructor("Object");
private static final Signature CSTRUCT_STRING_ARRAY = TypeUtils.parseConstructor("String[]");
private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object, Object)");
private static final Signature BEAN_MAP_PUT = TypeUtils.parseSignature("Object put(Object, Object, Object)");
private static final Signature KEY_SET = TypeUtils.parseSignature("java.util.Set keySet()");
private static final Signature NEW_INSTANCE = new Signature("newInstance", BEAN_MAP, new Type[]{Constants.TYPE_OBJECT});
private static final Signature GET_PROPERTY_TYPE = TypeUtils.parseSignature("Class getPropertyType(String)");
private static final Signature CAST_DATA_TYPE = TypeUtils.parseSignature("Object cast(Object,Class)");
private static final Signature TO_LOWER_CASE = TypeUtils.parseSignature("String toLowerCase()");
private static final Type TYPE_BASIC_DATA_CAST = TypeUtils.parseType(BasicDataCast.class.getName());
private final boolean ignoreKeyCase; public BeanMapEmitter(ClassVisitor v, String className, Class type, int require, boolean ignoreKeyCase) {
super(v);
this.ignoreKeyCase = ignoreKeyCase;
begin_class(Constants.V1_7, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
EmitUtils.null_constructor(this);
EmitUtils.factory_method(this, NEW_INSTANCE);
generateConstructor(); Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
Map<Object, Object> allProps = new HashMap<>();
allProps.putAll(getters);
allProps.putAll(setters); if (require != 0) {
for (Iterator it = allProps.keySet().iterator(); it.hasNext(); ) {
String name = (String) it.next();
if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
(((require & BeanMap.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();
} private String lowerCaseName(String name) {
return name.toLowerCase(Locale.US);
} private String underscoreName(String name) {
if (!StringUtils.hasLength(name)) {
return "";
}
StringBuilder result = new StringBuilder();
result.append(lowerCaseName(name.substring(0, 1)));
for (int i = 1; i < name.length(); i++) {
String s = name.substring(i, i + 1);
String slc = lowerCaseName(s);
if (!s.equals(slc)) {
result.append("_").append(slc);
} else {
result.append(s);
}
}
return result.toString();
} private Map makePropertyMap(PropertyDescriptor[] props) {
Map<Object, Object> names = new HashMap<>();
for (PropertyDescriptor pd : props) {
if (ignoreKeyCase) {
names.put(lowerCaseName(pd.getName()), pd);
String underscoredName = underscoreName(pd.getName());
if (!lowerCaseName(pd.getName()).equals(underscoredName)) {
names.put(underscoredName, pd);
}
} else {
names.put(pd.getName(), pd);
}
}
return names;
} @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
private String[] getNames(Map propertyMap) {
return (String[]) propertyMap.keySet().toArray(new String[propertyMap.size()]);
} 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();
} 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() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor) getters.get(key);
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
e.invoke(method);
e.box(method.getSignature().getReturnType());
e.return_value();
} public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
} 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);
//是否忽略大小写
if (ignoreKeyCase) {
e.invoke_virtual(Constants.TYPE_STRING, TO_LOWER_CASE);
}
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor) 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());
}
e.swap(); // move old value behind bean
e.load_arg(2); MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod());
Type setterType = write.getSignature().getArgumentTypes()[0];
EmitUtils.load_class(e, setterType);
e.invoke_static(TYPE_BASIC_DATA_CAST, CAST_DATA_TYPE);
e.box(Constants.TYPE_OBJECT); e.unbox(write.getSignature().getArgumentTypes()[0]);
e.invoke(write);
e.return_value();
} public void processDefault() {
// fall-through
}
});
e.aconst_null();
e.return_value();
e.end_method();
} 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();
} 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() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor) allProps.get(key);
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
e.return_value();
} public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)