1. 概述
在處理 Java 應用程序時,我們經常需要將數據從一個對象複製到另一個對象。 Spring Framework 的 Spring 框架 中的 BeanUtils.copyProperties 是複製 Bean 之間屬性的流行選擇。 但是,該方法默認會複製所有匹配的屬性。
有時,我們需要複製特定的字段,例如當源對象和目標對象具有不同的結構,或者當我們僅需要特定操作的字段子集時。 為了複製特定的字段而不是所有字段,我們需要自定義此行為。
在本教程中,我們將探索僅複製特定字段的不同方法及其示例。
2. 使用ignoreProperties選項
copyProperties方法允許傳入第三個參數ignoreProperties,該參數指定了不應從源對象複製到目標對象中的字段。我們可以將一個或多個屬性名稱作為 varargs 傳遞以排除(例如address, age)。
在這裏,我們將嘗試從SourceBean複製屬性到TargetBean。
public class SourceBean {
private String name;
private String address;
private int age;
// constructor and getters/setters here
}
public class TargetBean {
private String name;
private String address;
private int age;
// constructor and getters/setters here
}讓我們來看下面的示例,其中將第三個參數 address 傳遞給 BeanUtils.copyProperties,表示應將 address 屬性從 sourceBean 複製到 targetBean。
public class BeanUtilsCopyPropertiesUnitTest {
@Test
public void givenObjects_whenUsingIgnoreProperties_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TargetBean targetBean = new TargetBean();
BeanUtils.copyProperties(sourceBean, targetBean, "address");
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}
}在上述示例中,目標 Bean 對象中的 address 字段為 null 。
3. 使用自定義包裝器
我們可以創建一個實用方法,允許我們提及並複製特定的字段。 此方法將包裝 BeanUtils.copyProperties,並允許我們指定要複製和排除的字段:
public static void copySpecifiedProperties(Object source, Object target, Set<String> props) {
String[] excludedProperties = Arrays.stream(BeanUtils.getPropertyDescriptors(source.getClass()))
.map(PropertyDescriptor::getName)
.filter(name -> !props.contains(name))
.toArray(String[]::new);
BeanUtils.copyProperties(source, target, excludedProperties);
}在下面的示例中,目標是將name和age字段從sourceBean複製到targetBean,同時排除複製address字段:
@Test
public void givenObjects_whenUsingCustomWrapper_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TargetBean targetBean = new TargetBean();
BeanUtilsCopyProperties
.copySpecifiedProperties(sourceBean, targetBean, new HashSet<>(Arrays.asList("name", "age")));
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}4. 使用中間DTO對象
這種方法涉及創建一箇中間DTO對象,用於在將它們複製到目標對象之前過濾源對象中的特定字段。我們首先將源對象中的字段複製到中間DTO對象中,該對象是一個過濾後的表示。然後,我們將中間DTO對象中的過濾字段複製到目標對象中。
讓我們看一下TempDTO的結構:
public class TempDTO {
public String name;
public int age;
}現在,我們首先將特定字段從源Bean複製到實例中的tempDTO,然後再將tempDTO中的內容複製到目標Bean中。
@Test
public void givenObjects_whenUsingIntermediateObject_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TempDTO tempDTO = new TempDTO();
BeanUtils.copyProperties(sourceBean, tempDTO);
TargetBean targetBean = new TargetBean();
BeanUtils.copyProperties(tempDTO, targetBean);
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}5. 結論
本文探討了使用 Java 中的 BeanUtils.copyProperties 複製特定字段的各種方法。 ignoreProperties 參數提供了一種簡單直接的解決方案,而自定義包裝器和中間對象方法則在處理大量需要忽略的屬性時提供了更大的靈活性。
中間對象方法運行略慢,因為它執行了兩次複製操作,但它確保了分離關注點、防止不必要的複製以及允許靈活和選擇性的字段映射。