Created
January 6, 2017 07:30
-
-
Save pfmiles/cd6945785f1a7f07ea6678750ffd1cc1 to your computer and use it in GitHub Desktop.
使用from对象,update指定对象(to, 符合javaBean规范的pojo)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package test; | |
import java.beans.BeanInfo; | |
import java.beans.IntrospectionException; | |
import java.beans.Introspector; | |
import java.beans.PropertyDescriptor; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
import java.math.BigDecimal; | |
import java.math.BigInteger; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.Collection; | |
import java.util.Date; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.ListIterator; | |
import java.util.Map; | |
import java.util.concurrent.ConcurrentHashMap; | |
/** | |
* @author pf-miles Dec 14, 2016 3:59:00 PM | |
*/ | |
public class BeanUtil { | |
private static final String DATE_FMT_SIMPLE = "yyyy-MM-dd"; | |
private static final String DATE_FMT_NORMAL = "yyyy-MM-dd HH:mm:ss"; | |
private static final String DATE_FMT_FULL = "yyyy-MM-dd HH:mm:ssZ"; | |
// 'tryCreatePojoInstance'方法使用的,构造函数的缓存(可能是NULL对象) | |
private static final ConcurrentHashMap<Class<?>, Object> tryCreateInstConsCache = new ConcurrentHashMap<Class<?>, Object>( | |
16, 0.75f, BumonitorSdkConstants.CLIENT_CPU_NUM * 10); | |
// getter方法缓存: [cls, propName] -> method or NULL | |
private static final ConcurrentHashMap<Pair<Class<?>, String>, Object> readerCache = new ConcurrentHashMap<Pair<Class<?>, String>, Object>( | |
16, 0.75f, BumonitorSdkConstants.CLIENT_CPU_NUM * 10); | |
// setter方法缓存: [cls, propName] -> method or NULL | |
private static final ConcurrentHashMap<Pair<Class<?>, String>, Object> writerCache = new ConcurrentHashMap<Pair<Class<?>, String>, Object>( | |
16, 0.75f, BumonitorSdkConstants.CLIENT_CPU_NUM * 10); | |
/** | |
* 使用from对象,update指定对象(to, 符合javaBean规范的pojo);遵循javaBean规范映射(setter方法),若有任何属性缺失或名称不匹配则忽略; 但一旦属性名匹配上,就一定保证update成功,否则抛错;<br/> | |
* 当然也支持map、collection的update;<br/> | |
* 当from为null时,不做任何动作;<br/> | |
* 当to为null时,新建to同类型的对象,之后正常映射;<br/> | |
* 对于容器内部元素仅支持update, 不支持add, 即:被映射的目标不能为null | |
* | |
* @param from map作为数据来源方 | |
* @param toRef 将要被update的目标对象的ref | |
*/ | |
@SuppressWarnings("unchecked") | |
public static <T> void update(Object from, Ref<T> toRef, | |
Class<?> toCls) throws BumonitorSdkException { | |
// 若from是null则不用做任何事情 | |
if (from == null) | |
return; | |
// 若目标是基本类型及其wrapper类型或String、java.util.Date,则采用直接替换策略 | |
if (ClassUtil.isPrimitiveOrWrapper(toCls) || String.class.equals(toCls) | |
|| java.util.Date.class.equals(toCls)) { | |
toRef.setTarget((T) castToBaseTypes(from, toCls)); | |
return; | |
} | |
// 若target已排除是基本类型,且是null,则创建一个 | |
if (toRef.getTarget() == null) | |
toRef.setTarget((T) tryCreatePojoInstance(toCls)); | |
// 执行update策略 | |
if (Map.class.isAssignableFrom(toCls)) { | |
// update map | |
if (!(from instanceof Map)) | |
throw new BumonitorSdkException("Cannot update map using a non-map object, type: " | |
+ from.getClass().getName() + "."); | |
Map<Object, Object> toMap = (Map<Object, Object>) toRef.getTarget(); | |
Map<Object, Object> fromMap = (Map<Object, Object>) from; | |
for (Map.Entry<Object, Object> fromEntry : fromMap.entrySet()) { | |
// 遍历fromMap以确定本次处理希望update toMap的哪些字段 | |
Object fv = fromEntry.getValue(); | |
if (fv != null) { | |
Object k = fromEntry.getKey(); | |
if (toMap.containsKey(k)) { | |
Object tv = toMap.get(k); | |
if (tv != null) {// 对于容器内部元素仅支持update, 不支持add | |
Ref<Object> tr = new Ref<Object>(tv); | |
update(fv, tr, tv.getClass()); | |
toMap.put(k, tr.getTarget()); | |
} | |
} | |
} | |
} | |
} else if (Collection.class.isAssignableFrom(toCls)) { | |
// update collection | |
if (!(from instanceof Collection)) | |
throw new BumonitorSdkException( | |
"Cannot update collection using a non-collection object, type: " | |
+ from.getClass().getName() + "."); | |
if (List.class.isAssignableFrom(toCls)) { | |
// listIterator处理方式 | |
List<Object> toCol = (List<Object>) toRef.getTarget(); | |
Collection<Object> fromCol = (Collection<Object>) from; | |
// zipped遍历,fromCol对应位置元素若不为null, 则进行更新 | |
ListIterator<Object> toIter = toCol.listIterator(); | |
Iterator<Object> fromIter = fromCol.iterator(); | |
while (fromIter.hasNext() && toIter.hasNext()) { | |
Object fromObj = fromIter.next(); | |
Object toObj = toIter.next(); | |
if (fromObj != null && toObj != null) {// 仅支持update, 不支持add | |
Ref<Object> tr = new Ref<Object>(toObj); | |
update(fromObj, tr, toObj.getClass()); | |
toIter.set(tr.getTarget()); | |
} | |
} | |
} else { | |
// create new方式 | |
Collection<Object> newTo = (Collection<Object>) tryCreatePojoInstance(toCls); | |
Collection<Object> toCol = (Collection<Object>) toRef.getTarget(); | |
Collection<Object> fromCol = (Collection<Object>) from; | |
// zipped遍历,fromCol对应位置元素若不为null, 则进行更新,否则直接加入newTo; 最后需替换ref内的对象到newTo | |
Iterator<Object> toIter = toCol.iterator(); | |
Iterator<Object> fromIter = fromCol.iterator(); | |
while (toIter.hasNext()) { | |
Object tv = toIter.next(); | |
if (fromIter.hasNext()) { | |
Object fv = fromIter.next(); | |
if (fv != null && tv != null) { | |
Ref<Object> tr = new Ref<Object>(tv); | |
update(fv, tr, tv.getClass()); | |
tv = tr.getTarget(); | |
} | |
} | |
newTo.add(tv); | |
} | |
toRef.setTarget((T) newTo); | |
} | |
} else if (toCls.isArray()) { | |
// update array | |
if (!(from instanceof Collection)) | |
throw new BumonitorSdkException( | |
"Cannot update array using a non-collection object, type: " | |
+ from.getClass().getName() + "."); | |
T to = toRef.getTarget(); | |
Iterator<Object> fromIter = ((Collection<Object>) from).iterator(); | |
int arrSize = Array.getLength(to); | |
for (int i = 0; i < arrSize && fromIter.hasNext(); i++) { | |
Object fv = fromIter.next(); | |
if (fv != null) { | |
Object tv = Array.get(to, i); | |
Class<?> itype = null; | |
if (tv != null) { | |
itype = tv.getClass(); | |
} else { | |
Class<?> ctype = toCls.getComponentType(); | |
if (!ctype.isInterface() && !Modifier.isAbstract(ctype.getModifiers())) | |
itype = ctype; | |
} | |
if (itype != null) { | |
Ref<Object> tr = new Ref<Object>(tv); | |
update(fv, tr, itype); | |
Array.set(to, i, tr.getTarget()); | |
} | |
} | |
} | |
} else { | |
// update pojo | |
if (!(from instanceof Map)) | |
throw new BumonitorSdkException("Cannot update pojo using a non-map object, type: " | |
+ from.getClass().getName() + "."); | |
T to = toRef.getTarget(); | |
Map<Object, Object> fromMap = (Map<Object, Object>) from; | |
for (Map.Entry<Object, Object> fromEntry : fromMap.entrySet()) { | |
// 遍历fromMap以确定本次处理希望update toMap的哪些字段 | |
Object fv = fromEntry.getValue(); | |
if (fv != null) { | |
String k = String.valueOf(fromEntry.getKey()); | |
if (hasProperty(to, k)) { | |
Object tv = getProperty(to, k); | |
Class<?> itype = null; | |
if (tv != null) { | |
itype = tv.getClass(); | |
} else { | |
Class<?> ptype = getPropertyRetType(to, k); | |
if (ptype != null && !ptype.isInterface() | |
&& !Modifier.isAbstract(ptype.getModifiers())) | |
itype = ptype; | |
} | |
if (itype != null) { | |
Ref<Object> tr = new Ref<Object>(tv); | |
update(fv, tr, itype); | |
setProperty(to, k, tr.getTarget()); | |
} | |
} | |
} | |
} | |
} | |
} | |
private static Class<?> getPropertyRetType(Object obj, String propName) { | |
Object v = resolveReader(obj, propName); | |
if (Null.NULL.equals(v)) { | |
return null; | |
} else { | |
return ((Method) v).getReturnType(); | |
} | |
} | |
private static void setProperty(Object obj, String propName, Object value) { | |
Class<?> cls = obj.getClass(); | |
Pair<Class<?>, String> k = new Pair<Class<?>, String>(cls, propName); | |
Object v = writerCache.get(k); | |
if (v == null) { | |
// load v | |
BeanInfo bi = null; | |
try { | |
bi = Introspector.getBeanInfo(cls); | |
} catch (IntrospectionException e) { | |
SdkConfig.LOGGER.error("Error when introspecting class: " + cls.getName() + ".", e); | |
} | |
if (bi != null) | |
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) { | |
String pname = pd.getName(); | |
if ("class".equals(pname))// 忽略'getClass' | |
continue; | |
if (propName.equals(pname)) { | |
Method w = pd.getWriteMethod(); | |
if (w != null) { | |
w.setAccessible(true); | |
v = w; | |
} | |
} | |
} | |
if (v == null) | |
v = Null.NULL; | |
writerCache.put(k, v); | |
} | |
if (Null.NULL.equals(v)) { | |
SdkConfig.LOGGER.error("No writer method found when writing property: " + propName | |
+ ", obj: " + String.valueOf(obj) + "."); | |
} else { | |
try { | |
((Method) v).invoke(obj, value); | |
} catch (Exception e) { | |
SdkConfig.LOGGER | |
.error("Error when setting property: " + propName + ", obj: " | |
+ String.valueOf(obj) + ", val: " + String.valueOf(value) + ".", | |
e); | |
} | |
} | |
} | |
private static Object getProperty(Object obj, String propName) { | |
Object v = resolveReader(obj, propName); | |
if (Null.NULL.equals(v)) { | |
SdkConfig.LOGGER.error("No reader method found when reading property: " + propName | |
+ ", obj: " + String.valueOf(obj) + "."); | |
return null; | |
} else { | |
try { | |
return ((Method) v).invoke(obj); | |
} catch (Exception e) { | |
SdkConfig.LOGGER.error("Error when getting property: " + propName + ", obj: " | |
+ String.valueOf(obj) + ".", | |
e); | |
return null; | |
} | |
} | |
} | |
/** | |
* 对象身上是否存在指定名称的属性 | |
*/ | |
private static boolean hasProperty(Object obj, String propName) { | |
Object v = resolveReader(obj, propName); | |
return !Null.NULL.equals(v); | |
} | |
private static Object resolveReader(Object obj, String propName) { | |
Class<?> cls = obj.getClass(); | |
Pair<Class<?>, String> k = new Pair<Class<?>, String>(cls, propName); | |
Object v = readerCache.get(k); | |
if (v == null) { | |
// load v | |
BeanInfo bi = null; | |
try { | |
bi = Introspector.getBeanInfo(cls); | |
} catch (IntrospectionException e) { | |
SdkConfig.LOGGER.error("Error when introspecting class: " + cls.getName() + ".", e); | |
} | |
if (bi != null) | |
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) { | |
String pname = pd.getName(); | |
if ("class".equals(pname))// 忽略'getClass' | |
continue; | |
if (propName.equals(pname)) { | |
Method r = pd.getReadMethod(); | |
if (r != null) { | |
r.setAccessible(true); | |
v = r; | |
} | |
} | |
} | |
if (v == null) | |
v = Null.NULL; | |
readerCache.put(k, v); | |
} | |
return v; | |
} | |
/** | |
* 尝试创建指定javaBean类的新对象,本方法会依次尝试无参构造函数,然后参数由少到多的其它构造函数; 若没有任何public的构造函数或调用构造函数失败则抛错;方法本身带有可用构造函数cache | |
* @param cls 想要创建实例的类 | |
* @return 创建好的实例对象, 若有构造函数参数则全部为null | |
*/ | |
@SuppressWarnings("unchecked") | |
public static <T> T tryCreatePojoInstance(Class<T> cls) throws BumonitorSdkException { | |
try { | |
Object c = tryCreateInstConsCache.get(cls); | |
if (c == null) { | |
// 尝试找到参数最少的那个public构造函数,并放入缓存 | |
if (cls.isInterface() || Modifier.isAbstract(cls.getModifiers())) | |
throw new BumonitorSdkException( | |
"Cannot create instance of a interface or abstract class, class name: " | |
+ cls.getName() + "."); | |
Constructor<?>[] cs = cls.getConstructors(); | |
if (cs == null | cs.length == 0) { | |
c = Null.NULL; | |
} else { | |
for (Constructor<?> i : cs) | |
if (c == null | |
|| ((c instanceof Constructor) | |
&& consParamCount(i) < consParamCount((Constructor<?>) c))) | |
c = i; | |
if (c != null) { | |
((Constructor<?>) c).setAccessible(true);// boost reflection | |
} else { | |
c = Null.NULL; | |
} | |
} | |
tryCreateInstConsCache.put(cls, c); | |
} | |
if (Null.NULL.equals(c)) { | |
throw new BumonitorSdkException("No public constructor found for class: " | |
+ cls.getName() + ", try create instance failed."); | |
} else { | |
Constructor<?> cc = (Constructor<?>) c; | |
return (T) cc.newInstance(new Object[consParamCount(cc)]); | |
} | |
} catch (Exception e) { | |
if (e instanceof BumonitorSdkException) | |
throw (BumonitorSdkException) e; | |
else | |
throw new BumonitorSdkException( | |
"Error when trying to create instance of class: " + String.valueOf(cls) + ".", | |
e); | |
} | |
} | |
private static int consParamCount(Constructor<?> c) { | |
return c.getParameterTypes().length; | |
} | |
/** | |
* 将指定对象转换成指定类型的对象返回,该方法只针对基本类型及其包装类型,以及String、Date、Boolean、Character | |
*/ | |
@SuppressWarnings("unchecked") | |
public static <T> T castToBaseTypes(Object obj, | |
Class<T> targetType) throws BumonitorSdkException { | |
try { | |
if (obj == null) | |
return null; | |
if (targetType.isInstance(obj)) | |
return (T) obj; | |
if (String.class.equals(targetType)) | |
return (T) String.valueOf(obj); | |
if (java.util.Date.class.equals(targetType)) | |
return (T) parseDate(String.valueOf(obj)); | |
if (Boolean.class.equals(targetType) || boolean.class.equals(targetType)) | |
return (T) (Boolean) Boolean.parseBoolean(String.valueOf(obj)); | |
if (Character.class.equals(targetType) || char.class.equals(targetType)) | |
if (obj instanceof Number) { | |
return (T) Character.valueOf((char) ((Number) obj).intValue()); | |
} else { | |
return (T) Character.valueOf(String.valueOf(obj).charAt(0)); | |
} | |
if (Number.class.isAssignableFrom(targetType)) { | |
if (Number.class.isInstance(obj)) { | |
return convertNumber((Number) obj, targetType); | |
} else if (String.class.isInstance(obj)) { | |
return convertNumber(Double.parseDouble((String) obj), targetType); | |
} | |
} | |
return (T) obj; | |
} catch (Exception e) { | |
if (e instanceof BumonitorSdkException) | |
throw (BumonitorSdkException) e; | |
else | |
throw new BumonitorSdkException(e); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
private static <T> T convertNumber(Number n, Class<T> targetType) { | |
if (Byte.class.equals(targetType) || byte.class.equals(targetType)) | |
return (T) (Byte) n.byteValue(); | |
if (Short.class.equals(targetType) || short.class.equals(targetType)) | |
return (T) (Short) n.shortValue(); | |
if (Integer.class.equals(targetType) || int.class.equals(targetType)) | |
return (T) (Integer) n.intValue(); | |
if (Long.class.equals(targetType) || long.class.equals(targetType)) | |
return (T) (Long) n.longValue(); | |
if (Double.class.equals(targetType) || double.class.equals(targetType)) | |
return (T) (Double) n.doubleValue(); | |
if (Float.class.equals(targetType) || float.class.equals(targetType)) | |
return (T) (Float) n.floatValue(); | |
if (BigDecimal.class.equals(targetType)) | |
return (T) BigDecimal.valueOf(n.doubleValue()); | |
if (BigInteger.class.equals(targetType)) | |
return (T) BigInteger.valueOf(n.longValue()); | |
return (T) n; | |
} | |
/** | |
* 将string按照默认的三种格式转换成java.util.Date对象 | |
* @throws BumonitorSdkException | |
*/ | |
public static Date parseDate(String dateStr) throws BumonitorSdkException { | |
if (dateStr == null) | |
return null; | |
int len = dateStr.length(); | |
try { | |
if (DATE_FMT_NORMAL.length() == len) { | |
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FMT_NORMAL); | |
return sdf.parse(dateStr); | |
} else if (DATE_FMT_SIMPLE.length() == len) { | |
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FMT_SIMPLE); | |
return sdf.parse(dateStr); | |
} else if (DATE_FMT_NORMAL.length() + 5 == len) { | |
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FMT_FULL); | |
return sdf.parse(dateStr); | |
} else { | |
throw new ParseException("Unrecognized date format: " + dateStr + ".", 0); | |
} | |
} catch (ParseException e) { | |
throw new BumonitorSdkException(e); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package test; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import org.junit.Assert; | |
import org.junit.Test; | |
/** | |
* @author pf-miles Dec 15, 2016 4:51:59 PM | |
*/ | |
public class BeanUtilTest { | |
public static final class Pojo { | |
private String name; | |
private int age; | |
private Pojo2 p2; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public int getAge() { | |
return age; | |
} | |
public void setAge(int age) { | |
this.age = age; | |
} | |
public Pojo2 getP2() { | |
return p2; | |
} | |
public void setP2(Pojo2 p2) { | |
this.p2 = p2; | |
} | |
} | |
// 2参构造函数pojo | |
public static final class Pojo2 { | |
private String name; | |
private String gender; | |
public Pojo2(String p1, String p2) { | |
this.name = p1; | |
this.gender = p2; | |
} | |
public Pojo2(String p) { | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public String getGender() { | |
return gender; | |
} | |
public void setGender(String gender) { | |
this.gender = gender; | |
} | |
} | |
// 私有构造函数pojo | |
public static final class PriPojo { | |
private PriPojo() { | |
} | |
} | |
@SuppressWarnings("unchecked") | |
@Test | |
public void testTryCreatePojoInstance() throws BumonitorSdkException { | |
// pojo, 构造函数参数... | |
Pojo p = BeanUtil.tryCreatePojoInstance(Pojo.class); | |
Assert.assertTrue(p != null); | |
Pojo2 p2 = BeanUtil.tryCreatePojoInstance(Pojo2.class); | |
Assert.assertTrue(p2 != null); | |
// map/set/list | |
Map<String, Object> m = BeanUtil.tryCreatePojoInstance(HashMap.class); | |
Assert.assertTrue(m != null); | |
Set<String> s = BeanUtil.tryCreatePojoInstance(HashSet.class); | |
Assert.assertTrue(s != null); | |
List<String> l = BeanUtil.tryCreatePojoInstance(ArrayList.class); | |
Assert.assertTrue(l != null); | |
// 抛错情形 | |
try { | |
BeanUtil.tryCreatePojoInstance(PriPojo.class); | |
Assert.fail(); | |
} catch (BumonitorSdkException e) { | |
Assert.assertTrue(true); | |
} | |
} | |
@Test | |
public void testUpdate() throws BumonitorSdkException { | |
// 基本类型 | |
Ref<Integer> toRef = new Ref<Integer>(1); | |
BeanUtil.update(5, toRef, Integer.class); | |
Assert.assertTrue(new Integer(5).equals(toRef.getTarget())); | |
BeanUtil.update(7.5, toRef, Integer.class); | |
Assert.assertTrue(new Integer(7).equals(toRef.getTarget())); | |
BeanUtil.update("13", toRef, Integer.class); | |
Assert.assertTrue(new Integer(13).equals(toRef.getTarget())); | |
// pojo类型 | |
Pojo p = new Pojo(); | |
p.setName("wenyue"); | |
p.setAge(30); | |
Ref<Pojo> pojoRef = new Ref<Pojo>(p); | |
Map<String, Object> fromMap = new HashMap<String, Object>(); | |
fromMap.put("name", "weiwei"); | |
fromMap.put("age", 32); | |
BeanUtil.update(fromMap, pojoRef, Pojo.class); | |
Assert.assertTrue("weiwei".equals(p.getName())); | |
Assert.assertTrue(32 == p.getAge()); | |
fromMap.put("name", "xingyan"); | |
fromMap.put("age", 3); | |
BeanUtil.update(fromMap, pojoRef, Pojo.class); | |
Assert.assertTrue("xingyan".equals(p.getName())); | |
Assert.assertTrue(3 == p.getAge()); | |
Pojo2 p2 = new Pojo2("lihong", "female"); | |
p.setP2(p2); | |
fromMap.clear(); | |
Map<String, Object> p2Map = new HashMap<String, Object>(); | |
p2Map.put("name", "fuping"); | |
p2Map.put("gender", "male"); | |
fromMap.put("p2", p2Map); | |
BeanUtil.update(fromMap, pojoRef, Pojo.class); | |
Assert.assertTrue("fuping".equals(p.getP2().getName())); | |
Assert.assertTrue("male".equals(p.getP2().getGender())); | |
p2Map.put("name", "min"); | |
p2Map.put("gender", "female"); | |
BeanUtil.update(fromMap, pojoRef, Pojo.class); | |
Assert.assertTrue("min".equals(p.getP2().getName())); | |
Assert.assertTrue("female".equals(p.getP2().getGender())); | |
// map | |
fromMap.clear(); | |
Map<Object, Object> m = new HashMap<Object, Object>(); | |
m.put("name", "wenyue"); | |
m.put("age", 30); | |
Ref<Map<Object, Object>> mapRef = new Ref<Map<Object, Object>>(m); | |
fromMap.put("name", "weiwei"); | |
fromMap.put("age", 32); | |
BeanUtil.update(fromMap, mapRef, HashMap.class); | |
Assert.assertTrue("weiwei".equals(m.get("name"))); | |
Assert.assertTrue(new Integer(32).equals(m.get("age"))); | |
Map<Object, Object> m2 = new HashMap<Object, Object>(); | |
m2.put("name", "lihong"); | |
m2.put("age", 52); | |
m.put("m2", m2); | |
fromMap.clear(); | |
Map<String, Object> m2From = new HashMap<String, Object>(); | |
m2From.put("name", "xingyan"); | |
m2From.put("age", 3); | |
fromMap.put("m2", m2From); | |
BeanUtil.update(fromMap, mapRef, HashMap.class); | |
Assert.assertTrue("xingyan".equals(m2.get("name"))); | |
Assert.assertTrue(new Integer(3).equals(m2.get("age"))); | |
// collection, 分'in-place'更新形式和'create new'更新形式 | |
List<Object> inPlaceCol = new ArrayList<Object>(); | |
Map<String, Object> mi = new HashMap<String, Object>(); | |
mi.put("mapName", "mapName1"); | |
mi.put("mapAge", 10); | |
inPlaceCol.add(mi); | |
inPlaceCol.add(null); | |
Pojo pi = new Pojo(); | |
pi.setName("pojo1"); | |
pi.setAge(11); | |
Pojo2 pi2 = new Pojo2("pojo2", "male"); | |
pi.setP2(pi2); | |
inPlaceCol.add(pi); | |
Ref<Collection<Object>> inPlaceRef = new Ref<Collection<Object>>(inPlaceCol); | |
List<Map<String, Object>> fromCol = new ArrayList<Map<String, Object>>(); | |
Map<String, Object> fromMap1 = new HashMap<String, Object>(); | |
fromMap1.put("mapName", "wenyue"); | |
fromMap1.put("mapAge", 30); | |
fromCol.add(fromMap1); | |
fromCol.add(null); | |
Map<String, Object> fromMap2 = new HashMap<String, Object>(); | |
fromMap2.put("name", "weiwei"); | |
fromMap2.put("age", 32); | |
p2Map.clear(); | |
p2Map.put("name", "xingyan"); | |
p2Map.put("gender", "female"); | |
fromMap2.put("p2", p2Map); | |
fromCol.add(fromMap2); | |
BeanUtil.update(fromCol, inPlaceRef, ArrayList.class); | |
Assert.assertTrue(mi.get("mapName").equals("wenyue")); | |
Assert.assertTrue(mi.get("mapAge").equals(30)); | |
Assert.assertTrue(pi.getName().equals("weiwei")); | |
Assert.assertTrue(pi.getAge() == 32); | |
Assert.assertTrue(pi2.getName().equals("xingyan")); | |
Assert.assertTrue(pi2.getGender().equals("female")); | |
// array | |
Object[] arr = new Object[3]; | |
arr[0] = mi; | |
arr[1] = null; | |
arr[2] = pi; | |
fromMap1.put("mapName", "huimo"); | |
fromMap1.put("mapAge", 27); | |
fromMap2.put("name", "chanmu"); | |
fromMap2.put("age", 32); | |
p2Map.put("name", "yunchuan"); | |
p2Map.put("gender", "male"); | |
Ref<Object[]> arrRef = new Ref<Object[]>(arr); | |
BeanUtil.update(fromCol, arrRef, Object[].class); | |
Assert.assertTrue(mi.get("mapName").equals("huimo")); | |
Assert.assertTrue(mi.get("mapAge").equals(27)); | |
Assert.assertTrue(pi.getName().equals("chanmu")); | |
Assert.assertTrue(pi.getAge() == 32); | |
Assert.assertTrue(pi2.getName().equals("yunchuan")); | |
Assert.assertTrue(pi2.getGender().equals("male")); | |
// create new形式的col | |
Set<Object> createNewCol = new LinkedHashSet<Object>(); | |
createNewCol.add(mi); | |
createNewCol.add(pi); | |
fromMap1.put("mapName", "aaa"); | |
fromMap1.put("mapAge", 1111); | |
fromMap2.put("name", "bbb"); | |
fromMap2.put("age", 2222); | |
p2Map.put("name", "ccc"); | |
p2Map.put("gender", "dddd"); | |
Ref<Collection<?>> createNewColRef = new Ref<Collection<?>>(createNewCol); | |
fromCol.clear(); | |
fromCol.add(fromMap1); | |
fromCol.add(fromMap2); | |
BeanUtil.update(fromCol, createNewColRef, LinkedHashSet.class); | |
Assert.assertTrue(mi.get("mapName").equals("aaa")); | |
Assert.assertTrue(mi.get("mapAge").equals(1111)); | |
Assert.assertTrue(pi.getName().equals("bbb")); | |
Assert.assertTrue(pi.getAge() == 2222); | |
Assert.assertTrue(pi2.getName().equals("ccc")); | |
Assert.assertTrue(pi2.getGender().equals("dddd")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment