diff --git a/core-java/pom.xml b/core-java/pom.xml
index 5c1e9fcad0..e2983de9dd 100644
--- a/core-java/pom.xml
+++ b/core-java/pom.xml
@@ -78,6 +78,11 @@
jackson-databind
${jackson.version}
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+
@@ -468,6 +473,7 @@
2.8.5
+ 2.8.2
1.7.21
diff --git a/core-java/src/main/java/com/baeldung/deepcopy/Address.java b/core-java/src/main/java/com/baeldung/deepcopy/Address.java
new file mode 100644
index 0000000000..4e010ea92b
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/deepcopy/Address.java
@@ -0,0 +1,59 @@
+package com.baeldung.deepcopy;
+
+import java.io.Serializable;
+
+public class Address implements Serializable, Cloneable {
+
+ @Override
+ public Object clone() {
+ try {
+ return (Address) super.clone();
+ } catch (CloneNotSupportedException e) {
+ return new Address(this.street, this.getCity(), this.getCountry());
+ }
+ }
+
+ private static final long serialVersionUID = 1740913841244949416L;
+ private String street;
+ private String city;
+
+ private String country;
+
+ public Address(Address that) {
+ this(that.getStreet(), that.getCity(), that.getCountry());
+ }
+
+ public Address(String street, String city, String country) {
+ this.street = street;
+ this.city = city;
+ this.country = country;
+ }
+
+ public Address() {
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+}
+
diff --git a/core-java/src/main/java/com/baeldung/deepcopy/User.java b/core-java/src/main/java/com/baeldung/deepcopy/User.java
new file mode 100644
index 0000000000..329cfc6b27
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/deepcopy/User.java
@@ -0,0 +1,48 @@
+package com.baeldung.deepcopy;
+
+import java.io.Serializable;
+
+public class User implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = -3427002229954777557L;
+ private String firstName;
+ private String lastName;
+ private Address address;
+
+ public User(String firstName, String lastName, Address address) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.address = address;
+ }
+
+ public User(User that) {
+ this(that.getFirstName(), that.getLastName(), new Address(that.getAddress()));
+ }
+
+ public User() {
+ }
+
+ @Override
+ public Object clone() {
+ User user;
+ try {
+ user = (User) super.clone();
+ } catch (CloneNotSupportedException e) {
+ user = new User(this.getFirstName(), this.getLastName(), this.getAddress());
+ }
+ user.address = (Address) this.address.clone();
+ return user;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java
new file mode 100644
index 0000000000..196b69fbf7
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java
@@ -0,0 +1,128 @@
+package com.baeldung.deepcopy;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+
+public class DeepCopyUnitTest {
+
+ @Test
+ public void whenCreatingDeepCopyWithCopyConstructor_thenObjectsShouldNotBeSame() {
+
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+
+ User deepCopy = new User(pm);
+
+ assertThat(deepCopy).isNotSameAs(pm);
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenConstructorCopyShouldNotChange() {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ User deepCopy = new User(pm);
+
+ address.setCountry("Great Britain");
+
+ assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry());
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenCloneCopyShouldNotChange() {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ User deepCopy = (User) pm.clone();
+
+ address.setCountry("Great Britain");
+
+ assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry());
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenCommonsCloneShouldNotChange() {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ User deepCopy = (User) SerializationUtils.clone(pm);
+
+ address.setCountry("Great Britain");
+
+ assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry());
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenGsonCloneShouldNotChange() {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ Gson gson = new Gson();
+ User deepCopy = gson.fromJson(gson.toJson(pm), User.class);
+
+ address.setCountry("Great Britain");
+
+ assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry());
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenJacksonCopyShouldNotChange() throws IOException {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ ObjectMapper objectMapper = new ObjectMapper();
+ User deepCopy = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class);
+
+ address.setCountry("Great Britain");
+
+ assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry());
+ }
+
+ @Test
+ @Ignore
+ public void whenMakingCopies_thenShowHowLongEachMethodTakes() throws CloneNotSupportedException, IOException {
+ int times = 1000000;
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < times; i++) {
+ User primeMinisterClone = (User) SerializationUtils.clone(pm);
+ }
+ long end = System.currentTimeMillis();
+ System.out.println("Cloning with Apache Commons Lang took " + (end - start) + " milliseconds.");
+
+ start = System.currentTimeMillis();
+ Gson gson = new Gson();
+ for (int i = 0; i < times; i++) {
+ User primeMinisterClone = gson.fromJson(gson.toJson(pm), User.class);
+ }
+ end = System.currentTimeMillis();
+ System.out.println("Cloning with Gson took " + (end - start) + " milliseconds.");
+
+ start = System.currentTimeMillis();
+ for (int i = 0; i < times; i++) {
+ User primeMinisterClone = new User(pm);
+ }
+ end = System.currentTimeMillis();
+ System.out.println("Cloning with the copy constructor took " + (end - start) + " milliseconds.");
+
+ start = System.currentTimeMillis();
+ for (int i = 0; i < times; i++) {
+ User primeMinisterClone = (User) pm.clone();
+ }
+ end = System.currentTimeMillis();
+ System.out.println("Cloning with Cloneable interface took " + (end - start) + " milliseconds.");
+
+ start = System.currentTimeMillis();
+ ObjectMapper objectMapper = new ObjectMapper();
+ for (int i = 0; i < times; i++) {
+ User primeMinisterClone = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class);
+ }
+ end = System.currentTimeMillis();
+ System.out.println("Cloning with Jackson took " + (end - start) + " milliseconds.");
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java
new file mode 100644
index 0000000000..57660fadf1
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java
@@ -0,0 +1,33 @@
+package com.baeldung.deepcopy;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class ShallowCopyUnitTest {
+
+
+ @Test
+ public void whenShallowCopying_thenObjectsShouldNotBeSame() {
+
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+
+ User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress());
+
+ assertThat(shallowCopy)
+ .isNotSameAs(pm);
+ }
+
+ @Test
+ public void whenModifyingOriginalObject_thenCopyShouldChange() {
+ Address address = new Address("Downing St 10", "London", "England");
+ User pm = new User("Prime", "Minister", address);
+ User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress());
+
+ address.setCountry("Great Britain");
+
+ assertThat(shallowCopy.getAddress().getCountry())
+ .isEqualTo(pm.getAddress().getCountry());
+ }
+}