PropertyUtils.copyProperties 属性值复制失败
生活随笔
收集整理的這篇文章主要介紹了
PropertyUtils.copyProperties 属性值复制失败
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這兩天碰到了一個令人頭禿的問題,花費了我一整天的時間最終跟蹤到了問題根源:
@Testpublic void testOrderPage(){Page page = new Page();Pagination pagination = new Pagination(2,5);try {// 這里copy時,pagination中的current(2)和size(5)并沒有copy到page對象PropertyUtils.copyProperties(page, pagination);} catch (Exception e) {e.printStackTrace();}} public class Page {// ...protected long current = 1;// ...public long getCurrent() {return this.current;}// 根源就是在這里的set方法返回值不是voidpublic Page setCurrent(long current) {this.current = current;return this;}// ... }public class Pagination {// ...public Pagination(long current, long size) {if (current > 1) {this.current = current;}this.size = size;}// ...private long size = 10;private long current = 1;// ...public long getSize() {return size;}// ...public void setSize(long size) {this.size = size;}// ...public long getCurrent() {return current;}public void setCurrent(int current) {this.current = current;} }一路跟蹤下去
org\apache\commons\beanutils\PropertyUtils.java
public static void copyProperties(final Object dest, final Object orig){PropertyUtilsBean.getInstance().copyProperties(dest, orig); }org\apache\commons\beanutils\PropertyUtilsBean.java
public void copyProperties(final Object dest, final Object orig){if (...) {// ...} else /* if (orig is a standard JavaBean) */ {final PropertyDescriptor[] origDescriptors = getPropertyDescriptors(orig);for (PropertyDescriptor origDescriptor : origDescriptors) {final String name = origDescriptor.getName();// 跟蹤到這里的isWriteable,是判斷目標對象的name屬性是否可寫if (isReadable(orig, name) && isWriteable(dest, name)) {// ...}}} }public boolean isWriteable(Object bean, String name) {// ...// 為null的原因在這里 ↓final PropertyDescriptor desc = getPropertyDescriptor(bean, name);if (desc != null) {// 這里應該拿到目標對象屬性的set方法,但是為null,見上面 ↑Method writeMethod = getWriteMethod(bean.getClass(), desc);if (writeMethod == null) {// ...}return (writeMethod != null);} else {return (false);} }public PropertyDescriptor getPropertyDescriptor(Object bean, String name){// ...// 通過BeanIntrospectionData 對象的 getDescriptor 獲取屬性描述對象final BeanIntrospectionData data = getIntrospectionData(bean.getClass());PropertyDescriptor result = data.getDescriptor(name);// ...return result; }private BeanIntrospectionData getIntrospectionData(final Class<?> beanClass) {// ...// 這里還用了個緩存 descriptorsCache,通過 beanClass 獲取 BeanIntrospectionData 對象BeanIntrospectionData data = descriptorsCache.get(beanClass);if (data == null) {data = fetchIntrospectionData(beanClass);descriptorsCache.put(beanClass, data);}return data; }private BeanIntrospectionData fetchIntrospectionData(final Class<?> beanClass) {final DefaultIntrospectionContext ictx = new DefaultIntrospectionContext(beanClass);for (final BeanIntrospector bi : introspectors) {try {// 這里就是處理獲取 PropertyDescriptors 的地方,然后追蹤到 org.apache.commons.beanutils.DefaultBeanIntrospector#introspectbi.introspect(ictx);} catch (final IntrospectionException iex) {log.error("Exception during introspection", iex);}}// 這里會把處理后的 PropertyDescriptors 設置到 BeanIntrospectionData 里并返回return new BeanIntrospectionData(ictx.getPropertyDescriptors()); }?
org\apache\commons\beanutils\DefaultBeanIntrospector.java
public void introspect(final IntrospectionContext icontext) {// 通過 jdk 的 Introspector.getBeanInfo -> beanInfo.getPropertyDescriptors() 獲取 PropertyDescriptor[]BeanInfo beanInfo = null;try {beanInfo = Introspector.getBeanInfo(icontext.getTargetClass());} catch (final IntrospectionException e) { //... }PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();// ...icontext.addPropertyDescriptors(descriptors); }java\beans\Introspector.java
public static BeanInfo getBeanInfo(Class<?> beanClass){// ...// 這里獲取的 BeanInfo beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();// ...return beanInfo; }private BeanInfo getBeanInfo() throws IntrospectionException {// ...// 這里獲取的 PropertyDescriptor[]PropertyDescriptor pds[] = getTargetPropertyInfo();return new GenericBeanInfo(bd, esds, defaultEvent, pds,defaultProperty, mds, explicitBeanInfo); }private PropertyDescriptor[] getTargetPropertyInfo() {// ...// 跟蹤到這里發現在 PropertyInfo 中就沒有獲取到屬性的set方法,最終鎖定 ClassInfo.getProperties() 方法for (Map.Entry<String,PropertyInfo> entry : ClassInfo.get(this.beanClass).getProperties().entrySet()) {addPropertyDescriptor(null != entry.getValue().getIndexed()? new IndexedPropertyDescriptor(entry, this.propertyChangeSource): new PropertyDescriptor(entry, this.propertyChangeSource));}// ... }com\sun\beans\introspect\ClassInfo.java
public Map<String,PropertyInfo> getProperties() {if (this.properties == null) {synchronized (this.mutex) {if (this.properties == null) {this.properties = PropertyInfo.get(this.type);}}}return this.properties; }com\sun\beans\introspect\PropertyInfo.java
public static Map<String,PropertyInfo> get(Class<?> type) {List<Method> methods = ClassInfo.get(type).getMethods();if (methods.isEmpty()) {return Collections.emptyMap();}Map<String,PropertyInfo> map = new TreeMap<>();for (Method method : methods) {if (!Modifier.isStatic(method.getModifiers())) {Class<?> returnType = method.getReturnType();String name = method.getName();switch (method.getParameterCount()) {case 0:if (returnType.equals(boolean.class) && isPrefix(name, "is")) {PropertyInfo info = getInfo(map, name.substring(2), false);info.read = new MethodInfo(method, boolean.class);} else if (!returnType.equals(void.class) && isPrefix(name, "get")) {PropertyInfo info = getInfo(map, name.substring(3), false);info.readList = add(info.readList, method, method.getGenericReturnType());}break;case 1:// 最終就是在這里跳過了 set 方法,因為 returnType 不是 voidif (returnType.equals(void.class) && isPrefix(name, "set")) {PropertyInfo info = getInfo(map, name.substring(3), false);info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[0]);} else if (!returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "get")) {PropertyInfo info = getInfo(map, name.substring(3), true);info.readList = add(info.readList, method, method.getGenericReturnType());}break;case 2:if (returnType.equals(void.class) && method.getParameterTypes()[0].equals(int.class) && isPrefix(name, "set")) {PropertyInfo info = getInfo(map, name.substring(3), true);info.writeList = add(info.writeList, method, method.getGenericParameterTypes()[1]);}break;}}}Iterator<PropertyInfo> iterator = map.values().iterator();while (iterator.hasNext()) {if (!iterator.next().initialize()) {iterator.remove();}}return !map.isEmpty()? Collections.unmodifiableMap(map): Collections.emptyMap(); }?
總結
以上是生活随笔為你收集整理的PropertyUtils.copyProperties 属性值复制失败的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python爬取某鱼的直播间信息
- 下一篇: TraceView 的使用