工具类--BeanUtils----Bean转换工具
1 package com.zhouyy.netBank.util; 2 3 import java.beans.PropertyDescriptor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Modifier; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.HashMap; 10 import java.util.List; 11 import java.util.Map; 12 import java.util.concurrent.ConcurrentHashMap; 13 14 import org.springframework.beans.BeansException; 15 import org.springframework.beans.FatalBeanException; 16 import org.springframework.util.Assert; 17 import org.springframework.util.ClassUtils; 18 import org.springframework.util.CollectionUtils; 19 20 import com.zhouyy.netBank.framework.cglib.beans.BeanCopier; 21 import com.zhouyy.netBank.framework.cglib.beans.BeanMap; 22 23 /** 24 * Bean转换工具 25 * 26 * @author zhouyy 27 * @version 0.0.5 28 */ 29 public abstract class BeanUtils extends org.springframework.beans.BeanUtils { 30 31 private static final Map<String, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>(); 32 private static final Map<String, BeanCopier> NONE_NULL_BEAN_COPIER_MAP = new ConcurrentHashMap<>(); 33 34 /** 35 * MAP集合转成bean对象集合 36 * 37 * @param listResult 需要拷贝的集合 38 * @param clazz 需要将map转换成的Class 39 * @param <B> 泛型 40 * @return 集合泛型 41 * @author zhouyy 42 */ 43 public static <B> List<B> copyMapListProperties(List listResult, Class<B> clazz) { 44 List<B> sourceList = new ArrayList<>(); 45 Map<String, Object> cacheMap = new HashMap<>(); 46 //遍历MAP结果集 47 for (Object obj : listResult) { 48 Map map = (Map) obj; 49 B source = copyMapProperties(map, clazz, cacheMap); 50 // if (null != clazz) { 51 // source = copyMapProperties(map, clazz, cacheMap); 52 // } else { 53 // Map<String, Object> newMap = new HashMap<>(); 54 // Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator(); 55 // while (entries.hasNext()) { 56 // Map.Entry<String, Object> entry = entries.next(); 57 // newMap.put(entry.getKey().toLowerCase(), entry.getValue()); 58 // } 59 // source = (B) newMap; 60 // } 61 sourceList.add(source); 62 } 63 return sourceList; 64 } 65 66 /** 67 * MAP转成bean对象集合 68 * 69 * @param map 70 * @param clazz 71 * @param <B> 72 * @return 73 * @author zhouyy 74 */ 75 public static <B> B copyMapProperties(Map map, Class<B> clazz) { 76 Map<String, Object> cacheMap = new HashMap<>(); 77 return copyMapProperties(map, clazz, cacheMap); 78 } 79 80 /** 81 * 递归获取当前class的所有父类中的属性 82 * 83 * @param clazz 需要获取的类 84 * @param fieldList 字段集合 85 */ 86 public static void getAllFields(Class<?> clazz, List<Field> fieldList) { 87 Class superClass = clazz.getSuperclass(); 88 if (superClass != Object.class) { 89 getAllFields(superClass, fieldList); 90 } 91 Field[] fields = clazz.getDeclaredFields(); 92 fieldList.addAll(Arrays.asList(fields)); 93 } 94 95 /** 96 * MAP转成bean对象集合 97 * 98 * @param map 99 * @param clazz 100 * @param cacheMap 101 * @param <B> 102 * @return 103 * @author zhouyy 104 */ 105 @SuppressWarnings("unchecked") 106 private static <B> B copyMapProperties(Map map, Class<B> clazz, Map<String, Object> cacheMap) { 107 Assert.notNull(map, "map must not be null"); 108 Assert.notNull(clazz, "clazz must not be null"); 109 110 B instantiate = instantiate(clazz); 111 BeanMap beanMap = BeanMap.create(instantiate, true); 112 beanMap.putAll(map); 113 return instantiate; 114 115 // List<Field> fieldList = (List<Field>) cacheMap.get(clazz); 116 // if (fieldList == null) { 117 // fieldList = new ArrayList<>(); 118 // getAllFields(clazz, fieldList); 119 // } 120 // 121 // B source = null; 122 // try { 123 // source = clazz.newInstance(); 124 // } catch (InstantiationException | IllegalAccessException e) { 125 // e.printStackTrace(); 126 // } 127 // //遍历结果MAP 128 // Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); 129 // while (it.hasNext()) { 130 // Map.Entry<String, Object> entry = it.next(); 131 // //遍历映射实体属性 132 // for (Field field : fieldList) { 133 // String key = entry.getKey(); 134 // Boolean flag = (Boolean) cacheMap.get(key + field.getName()); 135 // if (flag == null) { 136 // flag = !key.replace("_", "").equalsIgnoreCase(field.getName()); 137 // cacheMap.put(key + field.getName(), flag); 138 // } 139 // if (flag) { 140 // continue; 141 // } 142 // 143 // Object value = entry.getValue(); 144 // Class typeClass = field.getType(); 145 // Object valueType = setFieldValueByFieldType(value, typeClass); 146 // ReflectionUtils.makeAccessible(field); 147 // ReflectionUtils.setField(field, source, valueType); 148 // } 149 // } 150 // return source; 151 } 152 153 // private static Object setFieldValueByFieldType(Object value, Class typeClass) { 154 // //这里去掉typeClass == double.class是为了代码规范,保证bean中的属性使用包装类 155 // if ((value instanceof Character) && typeClass == String.class) { 156 // Character character = (Character) value; 157 // value = character.toString(); 158 // }else if(value instanceof Number){ 159 // Number number = (Number) value; 160 // if (typeClass == BigDecimal.class) { 161 // value = BigDecimal.valueOf(number.doubleValue()); 162 // } else if (typeClass == BigInteger.class) { 163 // value = BigInteger.valueOf(number.longValue()); 164 // } else if (typeClass == Long.class) { 165 // value = number.longValue(); 166 // } else if (typeClass == Integer.class) { 167 // value = number.intValue(); 168 // } else if (typeClass == Double.class) { 169 // value = number.doubleValue(); 170 // } else if (typeClass == Float.class) { 171 // value = number.floatValue(); 172 // } else if (typeClass == Short.class) { 173 // value = number.shortValue(); 174 // } else if (typeClass == Byte.class) { 175 // value = number.byteValue(); 176 // } else { 177 // value = number; 178 // } 179 // } 180 // return value; 181 // } 182 private static String getBeanCopierCacheKey(Class source, Class target) { 183 return source.getName() + "|" + target.getName(); 184 } 185 186 private static BeanCopier getBeanCopier(Class source, Class target) { 187 String beanCopierCacheKey = getBeanCopierCacheKey(source, target); 188 BeanCopier beanCopier = BEAN_COPIER_MAP.get(beanCopierCacheKey); 189 if (beanCopier == null) { 190 beanCopier = BeanCopier.create(source, target, false); 191 BEAN_COPIER_MAP.put(beanCopierCacheKey, beanCopier); 192 } 193 return beanCopier; 194 } 195 196 private static BeanCopier getNoneNullBeanCopier(Class source, Class target) { 197 String beanCopierCacheKey = getBeanCopierCacheKey(source, target); 198 BeanCopier beanCopier = NONE_NULL_BEAN_COPIER_MAP.get(getBeanCopierCacheKey(source, target)); 199 if (beanCopier == null) { 200 beanCopier = BeanCopier.create(source, target, false, true); 201 NONE_NULL_BEAN_COPIER_MAP.put(beanCopierCacheKey, beanCopier); 202 } 203 return beanCopier; 204 } 205 206 /** 207 * 作者:zhouyy 208 * 批量转换List<Bean> 209 * 210 * @param source list集合 211 * @param t 所成对象的class 212 * @param <B> 213 * @return List<T> 214 * @throws BeansException 215 */ 216 public static <S, B> List<B> copyListProperties(List<S> source, Class<B> t) throws BeansException { 217 List<B> list = new ArrayList<>(); 218 if (CollectionUtils.isEmpty(source)) { 219 return list; 220 } 221 222 BeanCopier beanCopier = getBeanCopier(source.get(0).getClass(), t); 223 for (Object o : source) { 224 B instantiate = instantiate(t); 225 beanCopier.copy(o, instantiate, null); 226 // copyProperties(o, instantiate); 227 list.add(instantiate); 228 } 229 return list; 230 // List<B> list = new ArrayList<>(); 231 // if (source == null) { 232 // return list; 233 // } 234 // try { 235 // for (Object o : source) { 236 // B tObj = t.newInstance(); 237 // copyProperties(o, tObj); 238 // list.add(tObj); 239 // } 240 // } catch (InstantiationException | IllegalAccessException e) { 241 // e.printStackTrace(); 242 // } 243 // return list; 244 } 245 246 247 public static Map<String, Object> beanToMap(Object obj) { 248 BeanMap beanMap = BeanMap.create(obj); 249 HashMap<String, Object> copy = new HashMap<>(); 250 for (Object key : beanMap.keySet()) { 251 copy.put((String) key, beanMap.get(key)); 252 } 253 return copy; 254 // if (obj == null) { 255 // return null; 256 // } 257 // Map<String, Object> map = new HashMap<>(); 258 // try { 259 // BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); 260 // PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); 261 // for (PropertyDescriptor property : propertyDescriptors) { 262 // String key = property.getName(); 263 // // 过滤class属性 264 // if (!key.equals("class")) { 265 // // 得到property对应的getter方法 266 // Method getter = property.getReadMethod(); 267 // Object value = getter.invoke(obj); 268 // 269 // map.put(key, value); 270 // } 271 // } 272 // } catch (Exception e) { 273 // logger.error("transBean2Map Error {}", e); 274 // } 275 // return map; 276 } 277 278 /** 279 * 将两个对象集合合并,并且转换为Map集合 280 * 281 * @param listA 对象集合A 282 * @param listB 对象集合B 283 * @param key 根据对象中的哪个值进行合并 284 * @return 合并后的Map集合 285 */ 286 public static List<Map<String, Object>> mergeListBeanToMap(List<?> listA, List<?> listB, String key) { 287 List<Map<String, Object>> list = new ArrayList<>(); 288 for (Object objA : listA) { 289 //将对象转换为Map 290 Map<String, Object> mapA = beanToMap(objA); 291 for (Object objB : listB) { 292 //将对象转换为Map 293 Map<String, Object> mapB = beanToMap(objB); 294 //如果对象A和对象B的值一直,则合并两个对象Map 295 if (mapA.get(key).equals(mapB.get(key))) { 296 mapA.putAll(mapB); 297 } 298 } 299 //如果集合中不存在Map,则往List中追加合并后的Map 300 if (!list.contains(mapA)) { 301 list.add(mapA); 302 } 303 } 304 return list; 305 } 306 307 /** 308 * 将两个对象转换为map并做合并操作 309 * 310 * @param objA 对象A 311 * @param objB 对象B 312 * @param key 根据什么属性合并,属性名 313 * @return 合并后的Map 314 */ 315 public static Map<String, Object> mergeBeanToMap(Object objA, Object objB, String key) { 316 if (objA == null) { 317 return null; 318 } 319 Map<String, Object> mapA = beanToMap(objA); 320 if (objB == null) { 321 return mapA; 322 } 323 Map<String, Object> mapB = beanToMap(objB); 324 if (mapA.get(key).equals(mapB.get(key))) { 325 mapA.putAll(mapB); 326 } 327 return mapA; 328 } 329 330 /** 331 * 把source和target相同属性的value复制到target中 332 * 333 * @param source 准备赋值对象 334 * @param target 被赋值对象 335 * @throws BeansException 336 */ 337 public static void copyNotNullProperties(Object source, Object target) throws BeansException { 338 BeanCopier noneNullBeanCopier = getNoneNullBeanCopier(source.getClass(), target.getClass()); 339 noneNullBeanCopier.copy(source, target, null); 340 // copyProperties(source, target, null, null); 341 } 342 343 public static void copyNotNullProperties(Object source, Object target, String... ignoreProperties) throws BeansException { 344 copyProperties(source, target, null, ignoreProperties); 345 } 346 347 public static <B> B copyNewInstanceProperties(Object source, Class<B> t) throws BeansException { 348 BeanCopier beanCopier = getBeanCopier(source.getClass(), t); 349 B instantiate = instantiate(t); 350 beanCopier.copy(source, instantiate, null); 351 return instantiate; 352 // B tObj = null; 353 // try { 354 // tObj = t.newInstance(); 355 // } catch (InstantiationException | IllegalAccessException e) { 356 // logger.error("copyNewInstanceProperties Error {}", e); 357 // } 358 // copyProperties(source, tObj); 359 // return tObj; 360 } 361 362 private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException { 363 364 Assert.notNull(source, "Source must not be null"); 365 Assert.notNull(target, "Target must not be null"); 366 367 Class<?> actualEditable = target.getClass(); 368 if (editable != null) { 369 if (!editable.isInstance(target)) { 370 throw new IllegalArgumentException("Target class [" + target.getClass().getName() + 371 "] not assignable to Editable class [" + editable.getName() + "]"); 372 } 373 actualEditable = editable; 374 } 375 PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); 376 List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; 377 378 for (PropertyDescriptor targetPd : targetPds) { 379 Method writeMethod = targetPd.getWriteMethod(); 380 if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { 381 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); 382 if (sourcePd != null) { 383 Method readMethod = sourcePd.getReadMethod(); 384 if (readMethod != null && 385 ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { 386 try { 387 if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { 388 readMethod.setAccessible(true); 389 } 390 Object value = readMethod.invoke(source); 391 if (value != null) { //只拷贝不为null的属性 392 if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { 393 writeMethod.setAccessible(true); 394 } 395 writeMethod.invoke(target, value); 396 } 397 } catch (Throwable ex) { 398 throw new FatalBeanException( 399 "Could not copy property '" + targetPd.getName() + "' from source to target", ex); 400 } 401 } 402 } 403 } 404 } 405 } 406 }
1 // 2 // Source code recreated from a .class file by IntelliJ IDEA 3 // (powered by Fernflower decompiler) 4 // 5 6 package com.zhouyy.netBank.framework.cglib.beans; 7 8 import org.springframework.asm.ClassVisitor; 9 import org.springframework.asm.Label; 10 import org.springframework.asm.Type; 11 import org.springframework.cglib.core.*; 12 13 import java.beans.PropertyDescriptor; 14 import java.lang.reflect.Modifier; 15 import java.security.ProtectionDomain; 16 import java.util.HashMap; 17 import java.util.Map; 18 19 public abstract class BeanCopier { 20 private static final BeanCopier.BeanCopierKey KEY_FACTORY = (BeanCopier.BeanCopierKey) KeyFactory.create(BeanCopier.BeanCopierKey.class); 21 private static final Type CONVERTER = TypeUtils.parseType("org.springframework.cglib.core.Converter"); 22 private static final Type BEAN_COPIER = TypeUtils.parseType(BeanCopier.class.getName()); 23 private static final Signature COPY; 24 private static final Signature CONVERT; 25 26 public BeanCopier() { 27 } 28 29 public static BeanCopier create(Class source, Class target, boolean useConverter) { 30 BeanCopier.Generator gen = new BeanCopier.Generator(); 31 gen.setSource(source); 32 gen.setTarget(target); 33 gen.setUseConverter(useConverter); 34 return gen.create(); 35 } 36 37 public static BeanCopier create(Class source, Class target, boolean useConverter, boolean useNoneNull) { 38 BeanCopier.Generator gen = new BeanCopier.Generator(); 39 gen.setSource(source); 40 gen.setTarget(target); 41 gen.setUseConverter(useConverter); 42 gen.setUseNoneNull(useNoneNull); 43 return gen.create(); 44 } 45 46 public abstract void copy(Object var1, Object var2, Converter var3); 47 48 static { 49 COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER}); 50 CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)"); 51 } 52 53 public static class Generator extends AbstractClassGenerator { 54 private static final Source SOURCE = new Source(BeanCopier.class.getName()); 55 private Class source; 56 private Class target; 57 //使用转换器 58 private boolean useConverter; 59 //使用非空判断 60 private boolean useNoneNull; 61 62 public Generator() { 63 super(SOURCE); 64 } 65 66 public void setSource(Class source) { 67 if (!Modifier.isPublic(source.getModifiers())) { 68 this.setNamePrefix(source.getName()); 69 } 70 71 this.source = source; 72 } 73 74 public void setTarget(Class target) { 75 if (!Modifier.isPublic(target.getModifiers())) { 76 this.setNamePrefix(target.getName()); 77 } 78 79 this.target = target; 80 } 81 82 83 public void setUseNoneNull(boolean useNoneNull) { 84 this.useNoneNull = useNoneNull; 85 } 86 87 public void setUseConverter(boolean useConverter) { 88 this.useConverter = useConverter; 89 } 90 91 protected ClassLoader getDefaultClassLoader() { 92 return this.source.getClassLoader(); 93 } 94 95 protected ProtectionDomain getProtectionDomain() { 96 return ReflectUtils.getProtectionDomain(this.source); 97 } 98 99 public BeanCopier create() { 100 Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter,this.useNoneNull); 101 return (BeanCopier)super.create(key); 102 } 103 104 public void generateClass(ClassVisitor v) { 105 Type sourceType = Type.getType(source); 106 Type targetType = Type.getType(target); 107 ClassEmitter ce = new ClassEmitter(v); 108 ce.begin_class(Constants.V1_7, Constants.ACC_PUBLIC, getClassName(), BEAN_COPIER, null, Constants.SOURCE_FILE); 109 110 EmitUtils.null_constructor(ce); 111 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); 112 PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source); 113 PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target); 114 Map<Object, Object> names = new HashMap<>(); 115 116 for (int i = 0; i < getters.length; ++i) { 117 names.put(getters[i].getName(), getters[i]); 118 } 119 120 Local targetLocal = e.make_local(); 121 Local sourceLocal = e.make_local(); 122 if (this.useConverter) { 123 e.load_arg(1); 124 e.checkcast(targetType); 125 e.store_local(targetLocal); 126 e.load_arg(0); 127 e.checkcast(sourceType); 128 e.store_local(sourceLocal); 129 } else { 130 e.load_arg(1); 131 e.checkcast(targetType); 132 e.load_arg(0); 133 e.checkcast(sourceType); 134 } 135 136 for (int i = 0; i < setters.length; ++i) { 137 PropertyDescriptor setter = setters[i]; 138 PropertyDescriptor getter = (PropertyDescriptor) names.get(setter.getName()); 139 if (getter != null) { 140 Class<?> returnType = getter.getReadMethod().getReturnType(); 141 //是否为基本数据类型 true是,false否 142 boolean isPrimitive = returnType.isPrimitive(); 143 MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); 144 MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); 145 Type setterType = write.getSignature().getArgumentTypes()[0]; 146 if (this.useConverter) { 147 Label start = null; 148 if (this.useNoneNull && !isPrimitive) { 149 //将sourceLocal压入栈顶,以便在if处能获取到source对象的变量 150 e.load_local(sourceLocal); 151 //创建标签 152 start = e.make_label(); 153 //调用getter方法,获取值 154 e.invoke(read); 155 //进行非空判断 156 e.ifnull(start); 157 } 158 e.load_local(targetLocal); 159 e.load_arg(2); 160 e.load_local(sourceLocal); 161 e.invoke(read); 162 e.box(read.getSignature().getReturnType()); 163 EmitUtils.load_class(e, setterType); 164 e.push(write.getSignature().getName()); 165 e.invoke_interface(BeanCopier.CONVERTER, BeanCopier.CONVERT); 166 e.unbox_or_zero(setterType); 167 e.invoke(write); 168 169 if (start != null) { 170 //结束 171 e.mark(start); 172 } 173 } else if (compatible(getter, setter)) { 174 //如果是非空复制 175 Label start = null; 176 if (this.useNoneNull && !isPrimitive) { 177 //复制栈顶并进行压栈 178 e.dup(); 179 //创建标签 180 start = e.make_label(); 181 //调用getter方法,获取值 182 e.invoke(read); 183 //进行非空判断 184 e.ifnull(start); 185 } 186 e.dup2(); 187 e.invoke(read); 188 e.invoke(write); 189 if (start != null) { 190 //结束 191 e.mark(start); 192 } 193 } 194 } 195 } 196 e.return_value(); 197 e.end_method(); 198 ce.end_class(); 199 } 200 201 private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) { 202 return setter.getPropertyType().isAssignableFrom(getter.getPropertyType()); 203 } 204 205 protected Object firstInstance(Class type) { 206 return ReflectUtils.newInstance(type); 207 } 208 209 protected Object nextInstance(Object instance) { 210 return instance; 211 } 212 } 213 214 interface BeanCopierKey { 215 Object newInstance(String var1, String var2, boolean var3, boolean useNoneNull); 216 } 217 }
1 package com.zhouyy.netBank.framework.cglib.beans; 2 3 import java.math.BigDecimal; 4 import java.math.BigInteger; 5 6 /** 7 * 基础数据类型转换,在BeanMapEmitter使用cglib生成的代码中使用该类 8 * 9 * @author zhoul 10 * create time 2019-06-20 11 */ 12 public abstract class BasicDataCast { 13 14 public static Object cast(Object source, Class target) { 15 if(source == null){ 16 return null; 17 } 18 // 如果类型一致,则直接返回 19 if (source.getClass() == target) { 20 return source; 21 } 22 if (source instanceof Character) { 23 Character character = (Character) source; 24 if (target == String.class) { 25 return character.toString(); 26 } 27 } else if (source instanceof CharSequence) { 28 CharSequence character = (CharSequence) source; 29 if (target == String.class) { 30 return character.toString(); 31 } 32 } else if (source instanceof Number) { 33 Number number = (Number) source; 34 if (target == BigDecimal.class) { 35 return BigDecimal.valueOf(number.doubleValue()); 36 } else if (target == BigInteger.class) { 37 return BigInteger.valueOf(number.longValue()); 38 } else if (target == Long.class) { 39 return number.longValue(); 40 } else if (target == Integer.class) { 41 return number.intValue(); 42 } else if (target == Double.class) { 43 return number.doubleValue(); 44 } else if (target == Float.class) { 45 return number.floatValue(); 46 } else if (target == Short.class) { 47 return number.shortValue(); 48 } else if (target == Byte.class) { 49 return number.byteValue(); 50 }else if (target == String.class) { 51 return number.toString(); 52 } 53 } 54 return source; 55 } 56 }
1 package com.zhouyy.netBank.framework.cglib.beans; 2 3 import org.springframework.asm.ClassVisitor; 4 import org.springframework.cglib.core.AbstractClassGenerator; 5 import org.springframework.cglib.core.KeyFactory; 6 import org.springframework.cglib.core.ReflectUtils; 7 8 import java.security.ProtectionDomain; 9 import java.util.*; 10 11 /** 12 * A <code>Map</code>-based view of a JavaBean. The default set of keys is the 13 * union of all property names (getters or setters). An attempt to set 14 * a read-only property will be ignored, and write-only properties will 15 * be returned as <code>null</code>. Removal of objects is not a 16 * supported (the key set is fixed). 17 * 18 * @author Chris Nokleberg 19 * @author zhoul 20 */ 21 abstract public class BeanMap implements Map { 22 /** 23 * Limit the properties reflected in the key set of the map 24 * to readable properties. 25 * 26 * @see BeanMap.Generator#setRequire 27 */ 28 public static final int REQUIRE_GETTER = 1; 29 30 /** 31 * Limit the properties reflected in the key set of the map 32 * to writable properties. 33 * 34 * @see BeanMap.Generator#setRequire 35 */ 36 public static final int REQUIRE_SETTER = 2; 37 38 /** 39 * Helper method to create a new <code>BeanMap</code>. For finer 40 * control over the generated instance, use a new instance of 41 * <code>BeanMap.Generator</code> instead of this static method. 42 * 43 * @param bean the JavaBean underlying the map 44 * @return a new <code>BeanMap</code> instance 45 */ 46 public static BeanMap create(Object bean) { 47 Generator gen = new Generator(); 48 gen.setBean(bean); 49 return gen.create(); 50 } 51 52 /** 53 * 创建对象 54 * 55 * @param bean 56 * @param ignoreKeyCase 是否忽略KEY的大小写,要与putAllIgnoreKeyCase配合使用 57 * @return 58 */ 59 public static BeanMap create(Object bean, boolean ignoreKeyCase) { 60 Generator gen = new Generator(); 61 gen.setBean(bean); 62 gen.setIgnoreKeyCase(ignoreKeyCase); 63 return gen.create(); 64 } 65 66 public static class Generator extends AbstractClassGenerator { 67 private static final Source SOURCE = new Source(BeanMap.class.getName()); 68 69 private static final BeanMapKey KEY_FACTORY = 70 (BeanMapKey) KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); 71 72 interface BeanMapKey { 73 public Object newInstance(Class type, int require, boolean ignoreKeyCase); 74 } 75 76 private Object bean; 77 private Class beanClass; 78 private int require; 79 private boolean ignoreKeyCase; 80 81 public Generator() { 82 super(SOURCE); 83 } 84 85 public void setIgnoreKeyCase(boolean ignoreKeyCase) { 86 this.ignoreKeyCase = ignoreKeyCase; 87 } 88 89 /** 90 * Set the bean that the generated map should reflect. The bean may be swapped 91 * out for another bean of the same type using {@link #setBean}. 92 * Calling this method overrides any value previously set using {@link #setBeanClass}. 93 * You must call either this method or {@link #setBeanClass} before {@link #create}. 94 * 95 * @param bean the initial bean 96 */ 97 public void setBean(Object bean) { 98 this.bean = bean; 99 if (bean != null) 100 beanClass = bean.getClass(); 101 } 102 103 /** 104 * Set the class of the bean that the generated map should support. 105 * You must call either this method or {@link #setBeanClass} before {@link #create}. 106 * 107 * @param beanClass the class of the bean 108 */ 109 public void setBeanClass(Class beanClass) { 110 this.beanClass = beanClass; 111 } 112 113 /** 114 * Limit the properties reflected by the generated map. 115 * 116 * @param require any combination of {@link #REQUIRE_GETTER} and 117 * {@link #REQUIRE_SETTER}; default is zero (any property allowed) 118 */ 119 public void setRequire(int require) { 120 this.require = require; 121 } 122 123 protected ClassLoader getDefaultClassLoader() { 124 return beanClass.getClassLoader(); 125 } 126 127 protected ProtectionDomain getProtectionDomain() { 128 return ReflectUtils.getProtectionDomain(beanClass); 129 } 130 131 /** 132 * Create a new instance of the <code>BeanMap</code>. An existing 133 * generated class will be reused if possible. 134 */ 135 public BeanMap create() { 136 if (beanClass == null) { 137 throw new IllegalArgumentException("Class of bean unknown"); 138 } 139 setNamePrefix(beanClass.getName()); 140 return (BeanMap) super.create(KEY_FACTORY.newInstance(beanClass, require, ignoreKeyCase)); 141 } 142 143 public void generateClass(ClassVisitor v) throws Exception { 144 new BeanMapEmitter(v, getClassName(), beanClass, require, ignoreKeyCase); 145 } 146 147 protected Object firstInstance(Class type) { 148 return ((BeanMap) ReflectUtils.newInstance(type)).newInstance(bean); 149 } 150 151 protected Object nextInstance(Object instance) { 152 return ((BeanMap) instance).newInstance(bean); 153 } 154 } 155 156 /** 157 * Create a new <code>BeanMap</code> instance using the specified bean. 158 * This is faster than using the {@link #create} static method. 159 * 160 * @param bean the JavaBean underlying the map 161 * @return a new <code>BeanMap</code> instance 162 */ 163 abstract public BeanMap newInstance(Object bean); 164 165 /** 166 * Get the type of a property. 167 * 168 * @param name the name of the JavaBean property 169 * @return the type of the property, or null if the property does not exist 170 */ 171 abstract public Class getPropertyType(String name); 172 173 protected Object bean; 174 175 protected BeanMap() { 176 } 177 178 protected BeanMap(Object bean) { 179 setBean(bean); 180 } 181 182 public Object get(Object key) { 183 return get(bean, key); 184 } 185 186 public Object put(Object key, Object value) { 187 return put(bean, key, value); 188 } 189 190 /** 191 * Get the property of a bean. This allows a <code>BeanMap</code> 192 * to be used statically for multiple beans--the bean instance tied to the 193 * map is ignored and the bean passed to this method is used instead. 194 * 195 * @param bean the bean to query; must be compatible with the type of 196 * this <code>BeanMap</code> 197 * @param key must be a String 198 * @return the current value, or null if there is no matching property 199 */ 200 abstract public Object get(Object bean, Object key); 201 202 /** 203 * Set the property of a bean. This allows a <code>BeanMap</code> 204 * to be used statically for multiple beans--the bean instance tied to the 205 * map is ignored and the bean passed to this method is used instead. 206 * 207 * @param key must be a String 208 * @return the old value, if there was one, or null 209 */ 210 abstract public Object put(Object bean, Object key, Object value); 211 212 /** 213 * Change the underlying bean this map should use. 214 * 215 * @param bean the new JavaBean 216 * @see #getBean 217 */ 218 public void setBean(Object bean) { 219 this.bean = bean; 220 } 221 222 /** 223 * Return the bean currently in use by this map. 224 * 225 * @return the current JavaBean 226 * @see #setBean 227 */ 228 public Object getBean() { 229 return bean; 230 } 231 232 public void clear() { 233 throw new UnsupportedOperationException(); 234 } 235 236 public boolean containsKey(Object key) { 237 return keySet().contains(key); 238 } 239 240 public boolean containsValue(Object value) { 241 for (Iterator it = keySet().iterator(); it.hasNext(); ) { 242 Object v = get(it.next()); 243 if (((value == null) && (v == null)) || (value != null && value.equals(v))) 244 return true; 245 } 246 return false; 247 } 248 249 public int size() { 250 return keySet().size(); 251 } 252 253 public boolean isEmpty() { 254 return size() == 0; 255 } 256 257 public Object remove(Object key) { 258 throw new UnsupportedOperationException(); 259 } 260 261 public void putAll(Map t) { 262 for (Iterator it = t.keySet().iterator(); it.hasNext(); ) { 263 Object key = it.next(); 264 put(key, t.get(key)); 265 } 266 } 267 268 public boolean equals(Object o) { 269 if (o == null || !(o instanceof Map)) { 270 return false; 271 } 272 Map other = (Map) o; 273 if (size() != other.size()) { 274 return false; 275 } 276 for (Iterator it = keySet().iterator(); it.hasNext(); ) { 277 Object key = it.next(); 278 if (!other.containsKey(key)) { 279 return false; 280 } 281 Object v1 = get(key); 282 Object v2 = other.get(key); 283 if (!((v1 == null) ? v2 == null : v1.equals(v2))) { 284 return false; 285 } 286 } 287 return true; 288 } 289 290 public int hashCode() { 291 int code = 0; 292 for (Iterator it = keySet().iterator(); it.hasNext(); ) { 293 Object key = it.next(); 294 Object value = get(key); 295 code += ((key == null) ? 0 : key.hashCode()) ^ 296 ((value == null) ? 0 : value.hashCode()); 297 } 298 return code; 299 } 300 301 // TODO: optimize 302 public Set entrySet() { 303 HashMap<Object, Object> copy = new HashMap<>(); 304 for (Object key : keySet()) { 305 copy.put(key, get(key)); 306 } 307 return Collections.unmodifiableMap(copy).entrySet(); 308 } 309 310 public Collection values() { 311 Set keys = keySet(); 312 List<Object> values = new ArrayList<>(keys.size()); 313 for (Object key : keys) { 314 values.add(get(key)); 315 } 316 return Collections.unmodifiableCollection(values); 317 } 318 319 /* 320 * @see java.util.AbstractMap#toString 321 */ 322 public String toString() { 323 StringBuffer sb = new StringBuffer(); 324 sb.append('{'); 325 for (Iterator it = keySet().iterator(); it.hasNext(); ) { 326 Object key = it.next(); 327 sb.append(key); 328 sb.append('='); 329 sb.append(get(key)); 330 if (it.hasNext()) { 331 sb.append(", "); 332 } 333 } 334 sb.append('}'); 335 return sb.toString(); 336 } 337 }
1 package com.zhouyy.netBank.framework.cglib.beans; 2 3 import org.springframework.asm.ClassVisitor; 4 import org.springframework.asm.Label; 5 import org.springframework.asm.Type; 6 import org.springframework.cglib.beans.FixedKeySet; 7 import org.springframework.cglib.core.*; 8 import org.springframework.util.StringUtils; 9 10 import java.beans.PropertyDescriptor; 11 import java.util.HashMap; 12 import java.util.Iterator; 13 import java.util.Locale; 14 import java.util.Map; 15 16 class BeanMapEmitter extends ClassEmitter { 17 private static final Type BEAN_MAP = TypeUtils.parseType(BeanMap.class.getName()); 18 private static final Type FIXED_KEY_SET = TypeUtils.parseType(FixedKeySet.class.getName()); 19 private static final Signature CSTRUCT_OBJECT = TypeUtils.parseConstructor("Object"); 20 private static final Signature CSTRUCT_STRING_ARRAY = TypeUtils.parseConstructor("String[]"); 21 private static final Signature BEAN_MAP_GET = TypeUtils.parseSignature("Object get(Object, Object)"); 22 private static final Signature BEAN_MAP_PUT = TypeUtils.parseSignature("Object put(Object, Object, Object)"); 23 private static final Signature KEY_SET = TypeUtils.parseSignature("java.util.Set keySet()"); 24 private static final Signature NEW_INSTANCE = new Signature("newInstance", BEAN_MAP, new Type[]{Constants.TYPE_OBJECT}); 25 private static final Signature GET_PROPERTY_TYPE = TypeUtils.parseSignature("Class getPropertyType(String)"); 26 private static final Signature CAST_DATA_TYPE = TypeUtils.parseSignature("Object cast(Object,Class)"); 27 private static final Signature TO_LOWER_CASE = TypeUtils.parseSignature("String toLowerCase()"); 28 private static final Type TYPE_BASIC_DATA_CAST = TypeUtils.parseType(BasicDataCast.class.getName()); 29 private final boolean ignoreKeyCase; 30 31 public BeanMapEmitter(ClassVisitor v, String className, Class type, int require, boolean ignoreKeyCase) { 32 super(v); 33 this.ignoreKeyCase = ignoreKeyCase; 34 begin_class(Constants.V1_7, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE); 35 EmitUtils.null_constructor(this); 36 EmitUtils.factory_method(this, NEW_INSTANCE); 37 generateConstructor(); 38 39 Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type)); 40 Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type)); 41 Map<Object, Object> allProps = new HashMap<>(); 42 allProps.putAll(getters); 43 allProps.putAll(setters); 44 45 if (require != 0) { 46 for (Iterator it = allProps.keySet().iterator(); it.hasNext(); ) { 47 String name = (String) it.next(); 48 if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) || 49 (((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) { 50 it.remove(); 51 getters.remove(name); 52 setters.remove(name); 53 } 54 } 55 } 56 generateGet(type, getters); 57 generatePut(type, setters); 58 59 String[] allNames = getNames(allProps); 60 generateKeySet(allNames); 61 generateGetPropertyType(allProps, allNames); 62 end_class(); 63 } 64 65 private String lowerCaseName(String name) { 66 return name.toLowerCase(Locale.US); 67 } 68 69 private String underscoreName(String name) { 70 if (!StringUtils.hasLength(name)) { 71 return ""; 72 } 73 StringBuilder result = new StringBuilder(); 74 result.append(lowerCaseName(name.substring(0, 1))); 75 for (int i = 1; i < name.length(); i++) { 76 String s = name.substring(i, i + 1); 77 String slc = lowerCaseName(s); 78 if (!s.equals(slc)) { 79 result.append("_").append(slc); 80 } else { 81 result.append(s); 82 } 83 } 84 return result.toString(); 85 } 86 87 private Map makePropertyMap(PropertyDescriptor[] props) { 88 Map<Object, Object> names = new HashMap<>(); 89 for (PropertyDescriptor pd : props) { 90 if (ignoreKeyCase) { 91 names.put(lowerCaseName(pd.getName()), pd); 92 String underscoredName = underscoreName(pd.getName()); 93 if (!lowerCaseName(pd.getName()).equals(underscoredName)) { 94 names.put(underscoredName, pd); 95 } 96 } else { 97 names.put(pd.getName(), pd); 98 } 99 } 100 return names; 101 } 102 103 @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument") 104 private String[] getNames(Map propertyMap) { 105 return (String[]) propertyMap.keySet().toArray(new String[propertyMap.size()]); 106 } 107 108 private void generateConstructor() { 109 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null); 110 e.load_this(); 111 e.load_arg(0); 112 e.super_invoke_constructor(CSTRUCT_OBJECT); 113 e.return_value(); 114 e.end_method(); 115 } 116 117 private void generateGet(Class type, final Map getters) { 118 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null); 119 e.load_arg(0); 120 e.checkcast(Type.getType(type)); 121 e.load_arg(1); 122 e.checkcast(Constants.TYPE_STRING); 123 EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 124 public void processCase(Object key, Label end) { 125 PropertyDescriptor pd = (PropertyDescriptor) getters.get(key); 126 MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod()); 127 e.invoke(method); 128 e.box(method.getSignature().getReturnType()); 129 e.return_value(); 130 } 131 132 public void processDefault() { 133 e.aconst_null(); 134 e.return_value(); 135 } 136 }); 137 e.end_method(); 138 } 139 140 private void generatePut(Class type, final Map setters) { 141 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null); 142 e.load_arg(0); 143 e.checkcast(Type.getType(type)); 144 e.load_arg(1); 145 e.checkcast(Constants.TYPE_STRING); 146 //是否忽略大小写 147 if (ignoreKeyCase) { 148 e.invoke_virtual(Constants.TYPE_STRING, TO_LOWER_CASE); 149 } 150 EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 151 public void processCase(Object key, Label end) { 152 PropertyDescriptor pd = (PropertyDescriptor) setters.get(key); 153 if (pd.getReadMethod() == null) { 154 e.aconst_null(); 155 } else { 156 MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod()); 157 e.dup(); 158 e.invoke(read); 159 e.box(read.getSignature().getReturnType()); 160 } 161 e.swap(); // move old value behind bean 162 e.load_arg(2); 163 164 MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod()); 165 Type setterType = write.getSignature().getArgumentTypes()[0]; 166 EmitUtils.load_class(e, setterType); 167 e.invoke_static(TYPE_BASIC_DATA_CAST, CAST_DATA_TYPE); 168 e.box(Constants.TYPE_OBJECT); 169 170 e.unbox(write.getSignature().getArgumentTypes()[0]); 171 e.invoke(write); 172 e.return_value(); 173 } 174 175 public void processDefault() { 176 // fall-through 177 } 178 }); 179 e.aconst_null(); 180 e.return_value(); 181 e.end_method(); 182 } 183 184 private void generateKeySet(String[] allNames) { 185 // static initializer 186 declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null); 187 188 CodeEmitter e = begin_static(); 189 e.new_instance(FIXED_KEY_SET); 190 e.dup(); 191 EmitUtils.push_array(e, allNames); 192 e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY); 193 e.putfield("keys"); 194 e.return_value(); 195 e.end_method(); 196 197 // keySet 198 e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null); 199 e.load_this(); 200 e.getfield("keys"); 201 e.return_value(); 202 e.end_method(); 203 } 204 205 private void generateGetPropertyType(final Map allProps, String[] allNames) { 206 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null); 207 e.load_arg(0); 208 EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 209 public void processCase(Object key, Label end) { 210 PropertyDescriptor pd = (PropertyDescriptor) allProps.get(key); 211 EmitUtils.load_class(e, Type.getType(pd.getPropertyType())); 212 e.return_value(); 213 } 214 215 public void processDefault() { 216 e.aconst_null(); 217 e.return_value(); 218 } 219 }); 220 e.end_method(); 221 } 222 }