Copy Specific Fields via Spring BeanUtils.copyProperties Example
1. Introduction
In this example, I will demonstrate all the available methods to copy specific fields via BeanUtils.copyProperties in a Spring application. The Spring Framework’s BeanUtils class provides three static void copyProperties methods to copy properties from one bean to another.
- copyProperties(Object source, Object target) – copy the property values of the given
sourcebean into thetargetbean. - copyProperties(Object source, Object target, Class editable) – copy the property values of the given
sourcebean into the giventargetbean, only setting properties defined in the given “editable” class. - copyProperties(Object source, Object target, String… ignoreProperties) – copy the property values of the given
sourcebean into the giventargetbean but ignore the given “ignoreProperties“.
2. Setup
In this step, I will create a gradle project via Spring Initializr with the Lombok dependency. Here is the generated build.gradle file.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.4'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'org.zheng.demo.spring.beanutils'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}3. Java Beans
A JavaBean is a standard Java class with three conventions: all properties are private with getters and setters, has a public no-argument constructor, and implements the Serializable interface. In this step, I will create four Java Beans.
DtoPOJO– has six data members:age,email,isValid,name,notes, andrank.ModelPOJO– has five data members:age,isValid,name,notes, andrank.EditableTarget– has three data members:age,name, andrank. It is a subset ofDtoPOJOandModelPOJO.ModelPOJO2– extends fromEditableTargetand has a total of six data members:age,email,isValid,name,notes, andrank.
3.1 DtoPOJO
A DtoPOJO JavaBean has the following six data members:
private int age;private String email;private boolean isValid;private String name;private List <String> notes;private Integer rank;
DtoPOJO.java
package org.zheng.demo.spring.beanutils.dto;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class DtoPOJO implements Serializable {
private static final long serialVersionUID = -6849421475135764851L;
private int age;
private String email;
private boolean isValid;
private String name;
private List notes;
private Integer rank;
}
3.2 ModelPOJO
A ModelPOJO JavaBean is similar to the DtoPOJO with two differences: no primitive data type and without the email field. It has the following five data members:
private Integer age;private Boolean isValid;private String name;private List<String> notes;private Integer rank;
ModelPOJO.java
package org.zheng.demo.spring.beanutils.dto;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class ModelPOJO implements Serializable {
private static final long serialVersionUID = -1821365191492214587L;
private Integer age;
private Boolean isValid;
private String name;
private List notes;
private Number rank;
}
3.3 ModelPOJO2
A ModelPOJO2 JavaBean extends from EditableTarget and has three additional properties:
private String email;private List<String> notes;private Boolean isValid;
ModelPOJO2.java
package org.zheng.demo.spring.beanutils.dto;
import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
@Getter
@Setter
public class ModelPOJO2 extends EditableTarget {
private static final long serialVersionUID = 9064042642762325288L;
private String email;
private List notes;
private Boolean isValid;
}3.4 EditableTarget
An EditableTarget JavaBean has the following three data members:
privat Integer age;private String name;private Integer rank;
EditableTarget.java
package org.zheng.demo.spring.beanutils.dto;
import java.io.Serializable;
import lombok.Data;
@Data
public class EditableTarget implements Serializable {
private static final long serialVersionUID = -3717196137057564979L;
private Integer age;
private String name;
private Integer rank;
}
4. Copy Specific Fields Beanutils CopyProperties
In this step, I will copy the fields with BeanUtils.copyProperties methods utilizing the Java Beans created in step 3. Besides the exact type match, BeanUtils.copyProperties support primitive int to Integer copy. Here is the non-exhaustive set of examples of source and target property types that can be copied.
| Source Property Type | Target Property Type | copyProperties Supported? |
| Integer | Number | Yes |
| Number | Integer | No |
| boolean | Boolean | No |
| Boolean | boolean | No |
| int | Integer | Yes |
| Integer | int | Yes |
4.1 CopyDtoToModelTest
In this step, I will create a CopyDtoToModelTest.java to test the copyProperties methods.
test_copyProperties_default–copyProperties(source, target) method with the default copying.Note: theinttoIntegerandIntegertoNumberare copied.test_copyProperties_with_editableTarget_exception– thecopyProperties(source, target, EditableTarget.class)throws an exception becausemodelObjis not extended from theEditableTargetclass.test_copyProperties_with_editableTarget– using theModePOJO2as the destination object, noticed only the fields defined inEditableTargetare copied except therankfield. This is because therank‘s typeNumberis not copied to theIntegertype.test_copyProperties_with_ignored_fields– verify the ignored fields are not copied.
CopyDtoToModelTest.java
package org.zheng.demo.spring.beanutils.dto;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanUtils;
class CopyDtoToModelTest {
DtoPOJO dtoObj;
ModelPOJO modelObj;
@BeforeEach
void setup() {
dtoObj = new DtoPOJO();
modelObj = new ModelPOJO();
dtoObj.setAge(10);
dtoObj.setRank(1);
dtoObj.setName("Joe Smith");
dtoObj.setValid(true);
dtoObj.setNotes(List.of("note1", "note2"));
dtoObj.setEmail("test@Test.com");
}
@Test
void test_copyProperties_default() {
BeanUtils.copyProperties(dtoObj, modelObj);
// int to Integer is copied
assertEquals(10, modelObj.getAge());
// Integer to Number is copied
assertEquals(1, modelObj.getRank());
assertEquals("Joe Smith", modelObj.getName());
assertEquals(2, modelObj.getNotes().size());
assertEquals("note1", modelObj.getNotes().get(0));
assertEquals("note2", modelObj.getNotes().get(1));
// boolean to Boolean is NOT copied
assertNull(modelObj.getIsValid());
}
@Test
void test_copyProperties_with_editableTarget() {
ModelPOJO2 targetObj = new ModelPOJO2();
BeanUtils.copyProperties(dtoObj, targetObj, EditableTarget.class);
assertEquals(10, targetObj.getAge());
assertEquals("Joe Smith", targetObj.getName());
assertEquals(1, targetObj.getRank());
assertNull(targetObj.getEmail());
assertNull(targetObj.getIsValid());
assertNull(targetObj.getNotes());
}
@Test
void test_copyProperties_with_editableTarget_exception() {
assertThrows(IllegalArgumentException.class,
() -> BeanUtils.copyProperties(dtoObj, modelObj, EditableTarget.class));
}
@Test
void test_copyProperties_with_ignored_fields() {
BeanUtils.copyProperties(dtoObj, modelObj, "notes", "rank", "name");
// int to Integer is copied
assertEquals(10, modelObj.getAge());
// boolean to Boolean is NOT copied
assertNull(modelObj.getIsValid());
// ignored fields
assertNull(modelObj.getName());
assertNull(modelObj.getNotes());
assertNull(modelObj.getRank());
}
}
- Line 33:
copyPropertieswith onlysourceandtarget. The assertions verified the data is copied. - Line 52:
copyPropertieswithEditableTargetthrow an exception if the target is not extended from EditableTarget. - Line 59:
copyPropertieswithEditableTargetonly copies the fields from EditableTarget. - Line 73:
copyPropertiescopies the fields after ignoring the “notes“, “rank“, and “name” fields.
4.2 CopyModelToDtoTest
In this step, I will create a CopyModelToDtoTest.java to test the copyProperties methods.
test_copyProperties_default–copyProperties(source, target) method with the default copying.Note: theIntegertointis copied butNumbertoIntegeris not copied.test_copyProperties_with_editableTarget_exception– thecopyProperties(source, target, EditableTarget.class)throws an exception becausedtoObjis not extended from theEditableTargetclass.test_copyProperties_with_editableTarget– only the fields defined inEditableTargetare copied except therankfield becauseNumberis not copied toInteger.test_copyProperties_with_ignored_fields– verify the ignored fields are not copied.
CopyModelToDtoTest.java
package org.zheng.demo.spring.beanutils.dto;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanUtils;
class CopyModelToDtoTest {
DtoPOJO dtoObj;
ModelPOJO modelObj;
@BeforeEach
void setup() {
dtoObj = new DtoPOJO();
modelObj = new ModelPOJO();
modelObj.setAge(10);
modelObj.setRank(1);
modelObj.setName("Joe Smith");
modelObj.setIsValid(true);
modelObj.setNotes(List.of("note1", "note2"));
}
@Test
void test_copyProperties_default() {
BeanUtils.copyProperties(modelObj, dtoObj);
// Integer to int is copied
assertEquals(10, dtoObj.getAge());
// Number to Integer is NOT copied
assertNull(dtoObj.getRank());
// Boolean to boolean is NOT copied
assertFalse(dtoObj.isValid());
assertEquals("Joe Smith", dtoObj.getName());
assertEquals(2, dtoObj.getNotes().size());
assertEquals("note1", dtoObj.getNotes().get(0));
assertEquals("note2", dtoObj.getNotes().get(1));
}
@Test
void test_copyProperties_with_editableTarget_exception() {
assertThrows(IllegalArgumentException.class,
() -> BeanUtils.copyProperties(modelObj, dtoObj, EditableTarget.class));
}
@Test
void test_copyProperties_with_editableTarget() {
ModelPOJO2 targetObj = new ModelPOJO2();
BeanUtils.copyProperties(modelObj, targetObj, EditableTarget.class);
assertEquals(10, targetObj.getAge());
assertEquals("Joe Smith", targetObj.getName());
// Number to Integer is NOT copied
assertNull(targetObj.getRank());
assertNull(targetObj.getEmail());
assertNull(targetObj.getIsValid());
assertNull(targetObj.getNotes());
}
@Test
void test_copyProperties_with_ignored_fields() {
BeanUtils.copyProperties(modelObj, dtoObj, "notes", "name");
// Integer to int is copied
assertEquals(10, dtoObj.getAge());
// boolean to Boolean is NOT copied
assertFalse(dtoObj.isValid());
assertNull(dtoObj.getName());
assertNull(dtoObj.getNotes());
// Number to Integer is NOT copied
assertNull(dtoObj.getRank());
assertNull(dtoObj.getEmail());
}
}
- Line 33:
copyPropertieswith onlysourceandtarget. The assertions verified the data is copied. - Line 52:
copyPropertieswithEditableTargetthrow an exception because thedtoObjis not extended fromEditableTarget. - Line 59:
copyPropertieswithEditableTargetonly copies the fields fromEditableTarget. - Line 74:
copyPropertiescopies the fields after ignoring the “notes” and “name” fields.
5. Demo
In this step, I will run the tests and capture the test results.
6. Conclusion
In this example, I showed examples to copy specific fields beanutils copyproperties. When copying specific fields via the Spring BeanUtils.copyProperties method, 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.
7. Download
This was an example of a gradle project that copied specific fields between Java beans via BeanUtils.copyProperties.
You can download the full source code of this example here: Copy Specific Fields via Spring BeanUtils.copyProperties Example






