java 對象復制字段_利用Java反射機制實現對象相同字段的復制

一。如何實現不同類型對象之間的復制問題?

1、為什么會有這個問題?

近來在進行一個項目開發的時候,為了隱藏后端數據庫表結構、同時也為了配合給前端一個更友好的API接口文檔(swagger API文檔),我采用POJO來對應數據表結構,使用VO來給傳遞前端要展示的數據,同時使用DTO來進行請求參數的封裝。以上是一個具體的場景,可以發現這樣子一個現象:POJO、VO、DTO對象是同一個數據的不同視圖,所以會有很多相同的字段,由于不同的地方使用不同的對象,無可避免的會存在對象之間的值遷移問題,遷移的一個特征就是需要遷移的值字段相同。字段相同,于是才有了不同對象之間進行值遷移復制的問題。

2、現有的解決方法

一個一個的get出來后又set進去。這個方法無可避免會增加很多的編碼復雜度,還是一些很沒有營養的代碼,看多了還會煩,所以作為一個有點小追求的程序員都沒有辦法忍受這種摧殘。

使用別人已經存在的工具。在spring包里面有一個可以復制對象屬性的工具方法,可以進行對象值的復制,下一段我們詳細去分析它的這個工具方法。

自己動手豐衣足食。自己造工具來用,之所以自己造工具不是因為喜歡造工具,而是現有的工具沒辦法解決自己的需求,不得已而為之。

二、他山之石可以攻玉,詳談spring的對象復制工具

1、看看spring的對象復制工具到底咋樣?

類名:org.springframework.beans.BeanUtils

這個類里面所有的屬性復制的方法都調用了同一個方法,我們就直接分析這個原始的方法就行了。

/**

* Copy the property values of the given source bean into the given target bean.

*

Note: The source and target classes do not have to match or even be derived

* from each other, as long as the properties match. Any bean properties that the

* source bean exposes but the target bean does not will silently be ignored.

* @param source the source bean:也就是說要從這個對象里面復制值出去

* @param target the target bean:出去就是復制到這里面來

* @param editable the class (or interface) to restrict property setting to:這個類對象是target的父類或其實現的接口,用于控制屬性復制的范圍

* @param ignoreProperties array of property names to ignore:需要忽略的字段

* @throws BeansException if the copying failed

* @see BeanWrapper

*/

private static void copyProperties(Object source, Object target, Class> editable, String... ignoreProperties)

throws BeansException {

//這里在校驗要復制的對象是不可以為null的,這兩個方法可是會報錯的!!

Assert.notNull(source, "Source must not be null");

Assert.notNull(target, "Target must not be null");

//這里和下面的代碼就有意思了

Class> actualEditable = target.getClass();//獲取目標對象的動態類型

//下面判斷的意圖在于控制屬性復制的范圍

if (editable != null) {

//必須是target對象的父類或者其實現的接口類型,相當于instanceof運算符

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 ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

//重頭戲開始了!開始進行復制了

for (PropertyDescriptor targetPd : targetPds) {

//先判斷有沒有寫方法,沒有寫方法我也就沒有必要讀屬性出來了,這個懶偷的真好!

Method writeMethod = targetPd.getWriteMethod();

//首先,沒有寫方法的字段我不寫,乖巧撒?就是說你不讓我改我就不改,讓我忽略我就忽略!

if (writeMethod != null && (ignoreList == 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 (!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);

}

}

}

}

}

}

2、對復制工具的一些看法和總結

總結上一段代碼的分析,我們發現spring自帶的工具有以下特點:

它名副其實的是在復制屬性,而不是字段!!

它可以通過一個目標對象的父類或者其實現的接口來控制需要復制屬性的范圍

很貼心的可以忽略原對象的某些字段,可以通過2的方法忽略某些目標對象的字段

但是,這遠遠不夠!!!我需要如下的功能:

復制對象的字段,而不是屬性,也就是說我需要一個更暴力的復制工具。

我需要忽略原對象的某些字段,同時也能夠忽略目標對象的某些字段。

我的項目還需要忽略原對象為null的字段和目標對象不為null的字段

帶著這三個需求,開始我的工具制造。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/533058.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/533058.shtml
英文地址,請注明出處:http://en.pswp.cn/news/533058.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java 類確定運行時間_java回調函數實例:實現一個測試函數運行時間的工具類

下面使用java回調函數來實現一個測試函數運行時間的工具類:如果我們要測試一個類的方法的執行時間,通常我們會這樣做:public class TestObject {/*** 一個用來被測試的方法,進行了一個比較耗時的循環*/public static void testMet…

java socket調用接口_Java中socket接口調用

最近一個項目中接口通訊這一塊主要是調用銀聯系統的socket接口,我方是客戶端,即發送請求接收返回報文的一方。在貼代碼之前,還是要了解一下關于socket的基礎知識。Socket的基本概念1.建立連接當需要建立網絡連接時,必須…

protobuf java 編譯_Maven項目中,編譯proto文件成Java類

新建Maven項目新建一個 Maven 項目:pom定義了最小的maven2元素,即:groupId,artifactId,version。 groupId:項目或者組織的唯一標志,并且配置時生成的路徑也是由此生成,如org.codehaus.mojo生成的相對路徑為&#xff1a…

java 結構體數組初始化_C數組結構體聯合體快速初始化

背景C89標準規定初始化語句的元素以固定順序出現,該順序即待初始化數組或結構體元素的定義順序。C99標準新增指定初始化(Designated Initializer),即可按照任意順序對數組某些元素或結構體某些成員進行選擇性初始化,只需指明它們所對應的數組…

java override 訪問權限_java基礎之——訪問修飾符(private/default/protected/public)

1. 訪問修飾符介紹java中的訪問修飾符包含了四種:private、default(沒有對應的保留字)、protected和public。它們的含義如下:private:如果一個元素聲明為private,那么只有同一個類下的元素才可以訪問它。default:如果一…

python中scrapy可以爬取多少數據_python中scrapy框架爬取攜程景點數據

———————————————————————————————[版權申明:本文系作者原創,轉載請注明出處]文章出處:https://blog.csdn.net/sdksdk0/article/details/82381198作者:朱培 ID:sdksdk0——————…

python灰色關聯度分析代碼_灰色關聯分析法步驟 - osc_uwnmtz9n的個人空間 - OSCHINA - 中文開源技術交流社區...

https://wenku.baidu.com/view/dc356290af1ffc4fff47ac0d.html?rec_flagdefault&sxts1538121950212利用灰色關聯分析的步驟是:1.根據分析目的確定分析指標體系,收集分析數據。設n個數據序列形成如下矩陣:其中m為指標的個數&a…

aio 系統原理 Java_Java新一代網絡編程模型AIO原理及Linux系統AIO介紹

從JDK 7版本開始,Java新加入的文件和網絡io特性稱為nio2(new io 2, 因為jdk1.4中已經有過一個nio了),包含了眾多性能和功能上的改進,其中最重要的部分,就是對異步io的支持,稱為Java AIO(asynchronous IO)。因為AIO的實…

centos mysql 5.5 art_Linux?CentOS6.5下編譯安裝MySQL?5.5.51''''

一、編譯安裝MySQL前的準備工作安裝編譯源碼所需的工具和庫yum install gcc gcc-c ncurses-devel perl安裝cmake,從http://www.cmake.org下載源碼并編譯安裝wget http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gztar -xzvf cmake-2.8.10.2.tar.gzcd cmake-2.…

java修改默認字符編碼_設置默認的Java字符編碼?

如何以編程方式正確設置JVM(1.5.x)使用??的默認字符編碼?我已經讀過-Dfile.encoding 以前是以往的方式去為舊的JVM …我沒有那么奢侈的原因,我不會進入。我努力了:System.setProperty("file.encoding", "UTF-8");并且屬…

java api 第一個類是_JAVA常用API:String 類的常用方法

字符串是一個對象,有很多方法可以使用1. length();返回字符串的長度String str "abcd";int len str.length();2. isEmpty(); 僅當當length()為0時返回true,否則返回falseboolean b str.isEmpty();3. getBytes();返回字符串中每個字符的ASCII碼(使用平臺…

關于java內容_關于java一些概念性的內容

PO:persistant object持久對象最形象的理解就是一個PO就是數據庫中的一條記錄。好處是可以把一條記錄作為一個對象處理,可以方便的轉為其它對象。--------------------------------------------------------------------------------BO:busin…

java訂單類_基于Java創建一個訂單類代碼實例

這篇文章主要介紹了基于Java創建一個訂單類代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下需求描述定義一個類,描述訂單信息訂單id訂單所屬用戶(用戶對象)訂單所包含的商品(不定數量個商品對…

java請假審批怎么實現_java實現請假時間判斷

筆記:需求分析:每周上班6天夏季早上8:30-12:00下午14:00-17:30冬季早上8:30-12:00下午14:30-18:00請假最低為半天按照上午8:00-12:00,下午14:00-18:00計算,包括了夏季和冬季時間,規律分布如下public String getDouble(HttpServletRequest request) throws ParseException {//參…

mariadb mysql 5.6_MySQL / MariaDB 5.5 升級到 MySQL 5.6

RHEL 及 CentOS 7 默認的資庫系統是 MariaDB 5.5 (等同 MySQL 5.5), 雖然現時 MySQL 最新版是 5.7, 但一般上升級都建議一級一級上, 而 MySQL 5.6 比 5.5 也提高了效能及提供更多功能, 以下是在 RHEL 及 CentOS 從原來的 MySQL 5.5 或 MariaDB 5.5, 升級到 MySQL 5.6 的步驟。1…

iText報表Java_(例)Java生成PDF報表 iText

// 導入IO庫類import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;// 導入 PO&#x…

mysql update修改數據_MySQL UPDATE:修改數據(更新數據)

在 MySQL 中,可以使用 UPDATE 語句來修改、更新一個或多個表的數據。UPDATE 語句的基本語法使用 UPDATE 語句修改單個表,語法格式為:UPDATE SET 字段 1值 1 [,字段 2值 2… ] [WHERE 子句 ][ORDER BY 子句] [LIMIT 子句]語法說明如下&#xf…

java堆內存 數據結構_JAVA內存區域

首先解釋下內存溢出和內存泄露之間的區別,為后面的學習做些鋪墊:1、內存溢出和內存泄露的區別和聯系內存溢出 out of memory:是指程序申請內存時,沒有足夠的內存供申請者使用,或者說,給了你一塊存儲int類型…

java jsp的指令_[javaEE] jsp的指令

jsp的指令:jsp的指令(directive)是為jsp引擎而設計的,他們并不直接產生任何可見輸出,而是告訴引擎如何處理jsp頁面中的其他部分頁面頭部的page指令pageEncoding"utf-8"%>配置錯誤頁面:web.xml500/500.jsp404/404.jsp…

JAVA不能滿屏_java – 全屏幕視頻,不拉伸視頻

像這樣,你可以自己設置視頻的屬性。使用SurfaceView(給你更多的視圖控制),將其設置為fill_parent以匹配整個屏幕android:orientation"vertical"android:layout_width"match_parent"android:layout_height"fill_parent">…