Skip to content

Commit 8a6032c

Browse files
authored
Merge pull request #823 from hangga/cloning-object
KTLN-351 | Cloning an object in Kotlin | Hangga Aji Sayekti
2 parents 7ff924a + bafce25 commit 8a6032c

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package com.baeldung.cloningobject
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
6+
data class Address(var street: String, var city: String) : Cloneable {
7+
8+
public override fun clone() = Address(this.street, this.city)
9+
10+
constructor(address: Address) : this(address.street, address.city)
11+
12+
fun deepCopy(
13+
street: String = this.street,
14+
city: String = this.city,
15+
) = Address(street, city)
16+
}
17+
18+
data class Person(var name: String, var address: Address) : Cloneable {
19+
20+
public override fun clone() = Person(name, this.address.clone())
21+
22+
constructor(person: Person) : this(person.name, Address(person.address))
23+
24+
fun deepCopy(
25+
name: String = this.name,
26+
address: Address = this.address.deepCopy(),
27+
) = Person(name, address)
28+
}
29+
30+
data class Company(var name: String, var industry: String, val ceo: Person, val employees: List<Person>) : Cloneable {
31+
32+
public override fun clone() = Company(name, industry, ceo.clone(), employees.map { it.clone() })
33+
34+
constructor(company: Company) : this(company.name,
35+
company.industry,
36+
Person(company.ceo),
37+
company.employees.map { Person(it) })
38+
39+
fun deepCopy(
40+
name: String = this.name,
41+
industry: String = this.industry,
42+
ceo: Person = this.ceo.deepCopy(),
43+
employees: List<Person> = this.employees.map { it.deepCopy() },
44+
) = Company(name, industry, ceo, employees)
45+
}
46+
47+
data class Organization(var name: String, val headquarters: Address, val companies: List<Company>) : Cloneable {
48+
49+
public override fun clone() = Organization(name, headquarters.clone(), companies.map { it.clone() })
50+
51+
constructor(organization: Organization) : this(organization.name,
52+
Address(organization.headquarters),
53+
organization.companies.map { Company(it) })
54+
55+
fun deepCopy(
56+
name: String = this.name,
57+
headquarters: Address = this.headquarters.deepCopy(),
58+
companies: List<Company> = this.companies.map { it.deepCopy() },
59+
) = Organization(name, headquarters, companies)
60+
}
61+
62+
class CloningObjectUnitTest {
63+
64+
private val personHangga = Person("Hangga Aji Sayekti", Address("Jln. Kemasan No 53", "Yogyakarta"))
65+
private val personRaihan = Person("Raihan Kusumo", Address("Jln. Cikapayang No. 508", "Medan"))
66+
private val personLayla = Person("Layla Hinchcliffe", Address("Collins Street", "Melbourne"))
67+
private val companyBasen = Company("Basen Software", "Tech", personHangga, listOf(personRaihan, personLayla))
68+
69+
private val personBima = Person("Bima Arya", Address("Jl. Colombo No. 7", "Yogyakarta"))
70+
private val personDina = Person("Dina Fitriani", Address("Jl. Kaliurang No. 12", "Yogyakarta"))
71+
private val personCindy = Person("Cindy Claudia", Address("Jl. Atmosukarto No. 1", "Yogyakarta"))
72+
private val companyKotagede = Company("Kotagede Software", "Tech", personBima, listOf(personCindy, personDina))
73+
74+
private val organization = Organization("Bekraf", Address("Jalan Medan Merdeka Selatan", "Jakarta"), listOf(companyBasen, companyKotagede))
75+
76+
private fun modifyOrganization() {
77+
organization.name = "New Org Name"
78+
organization.headquarters.city = "New City"
79+
organization.companies.first().name = "New Company Name"
80+
organization.companies.first().ceo.name = "New CEO Name"
81+
organization.companies.first().ceo.address.city = "New CEO Address City Name"
82+
organization.companies.first().employees.first().name = "New Employee Name"
83+
organization.companies.first().employees.first().address.city = "New Employee Address City Name"
84+
}
85+
86+
@Test
87+
fun `when cloned object with secondary constructor then proves that deep copy`() {
88+
val clonedOrganization = Organization(organization)
89+
90+
modifyOrganization()
91+
92+
assertThat(clonedOrganization)
93+
.isNotSameAs(organization)
94+
assertThat(clonedOrganization.headquarters.city)
95+
.isNotEqualTo("New City")
96+
assertThat(clonedOrganization.companies.first().name)
97+
.isNotEqualTo("New Company Name")
98+
assertThat(clonedOrganization.companies.first().ceo.name)
99+
.isNotEqualTo("New CEO Name")
100+
assertThat(clonedOrganization.companies.first().ceo.address.city)
101+
.isNotEqualTo("New CEO Address City Name")
102+
assertThat(clonedOrganization.companies.first().employees.first().name)
103+
.isNotEqualTo("New Employee Name")
104+
assertThat(clonedOrganization.companies.first().employees.first().address.city)
105+
.isNotEqualTo("New Employee Address City Name")
106+
}
107+
108+
@Test
109+
fun `when cloned object with deepCopy() then proves that deep copy`() {
110+
val clonedOrganization = organization.deepCopy()
111+
112+
modifyOrganization()
113+
114+
assertThat(clonedOrganization)
115+
.isNotSameAs(organization)
116+
assertThat(clonedOrganization.headquarters.city)
117+
.isNotEqualTo("New City")
118+
assertThat(clonedOrganization.companies.first().name)
119+
.isNotEqualTo("New Company Name")
120+
assertThat(clonedOrganization.companies.first().ceo.name)
121+
.isNotEqualTo("New CEO Name")
122+
assertThat(clonedOrganization.companies.first().ceo.address.city)
123+
.isNotEqualTo("New CEO Address City Name")
124+
assertThat(clonedOrganization.companies.first().employees.first().name)
125+
.isNotEqualTo("New Employee Name")
126+
assertThat(clonedOrganization.companies.first().employees.first().address.city)
127+
.isNotEqualTo("New Employee Address City Name")
128+
}
129+
130+
@Test
131+
fun `when cloned object with clone() then proves that deep copy`() {
132+
val clonedOrganization = organization.clone()
133+
134+
modifyOrganization()
135+
136+
assertThat(clonedOrganization)
137+
.isNotSameAs(organization)
138+
assertThat(clonedOrganization.headquarters.city)
139+
.isNotEqualTo("New City")
140+
assertThat(clonedOrganization.companies.first().name)
141+
.isNotEqualTo("New Company Name")
142+
assertThat(clonedOrganization.companies.first().ceo.name)
143+
.isNotEqualTo("New CEO Name")
144+
assertThat(clonedOrganization.companies.first().ceo.address.city)
145+
.isNotEqualTo("New CEO Address City Name")
146+
assertThat(clonedOrganization.companies.first().employees.first().name)
147+
.isNotEqualTo("New Employee Name")
148+
assertThat(clonedOrganization.companies.first().employees.first().address.city)
149+
.isNotEqualTo("New Employee Address City Name")
150+
}
151+
152+
@Test
153+
fun `when cloned object with copy() then proves that shallow copy`() {
154+
val clonedOrganization = organization.copy()
155+
156+
modifyOrganization()
157+
158+
assertThat(clonedOrganization)
159+
.isNotSameAs(organization)
160+
assertThat(clonedOrganization.headquarters.city)
161+
.isEqualTo("New City")
162+
assertThat(clonedOrganization.companies.first().name)
163+
.isEqualTo("New Company Name")
164+
assertThat(clonedOrganization.companies.first().ceo.name)
165+
.isEqualTo("New CEO Name")
166+
assertThat(clonedOrganization.companies.first().ceo.address.city)
167+
.isEqualTo("New CEO Address City Name")
168+
assertThat(clonedOrganization.companies.first().employees.first().name)
169+
.isEqualTo("New Employee Name")
170+
assertThat(clonedOrganization.companies.first().employees.first().address.city)
171+
.isEqualTo("New Employee Address City Name")
172+
}
173+
174+
@Test
175+
fun `when cloned object with copy() then proves that deep copy`() {
176+
177+
val clonedOrganization = organization.copy(
178+
headquarters = organization.headquarters.copy(),
179+
companies = organization.companies.map { company ->
180+
company.copy(
181+
ceo = company.ceo.copy(
182+
address = company.ceo.address.copy()
183+
),
184+
employees = company.employees.map { employee ->
185+
employee.copy(
186+
address = employee.address.copy()
187+
)
188+
}
189+
)
190+
}
191+
)
192+
193+
modifyOrganization()
194+
195+
assertThat(clonedOrganization)
196+
.isNotSameAs(organization)
197+
assertThat(clonedOrganization.headquarters.city)
198+
.isNotEqualTo("New City")
199+
assertThat(clonedOrganization.companies.first().name)
200+
.isNotEqualTo("New Company Name")
201+
assertThat(clonedOrganization.companies.first().ceo.name)
202+
.isNotEqualTo("New CEO Name")
203+
assertThat(clonedOrganization.companies.first().ceo.address.city)
204+
.isNotEqualTo("New CEO Address City Name")
205+
assertThat(clonedOrganization.companies.first().employees.first().name)
206+
.isNotEqualTo("New Employee Name")
207+
assertThat(clonedOrganization.companies.first().employees.first().address.city)
208+
.isNotEqualTo("New Employee Address City Name")
209+
}
210+
}

0 commit comments

Comments
 (0)