코틀린 class 의 properties 개수가 많고, 이의 fields 가 반복되는 규칙의 이름을 가진 경우, objectMapper 를 통해 쉽게 값을 사용할 수 있다.
어떤 경우에 이런 기능이 필요할까? 필자가 개발하다 보니, 인수인계 받은 코드의 item class 의 프로퍼티가 매우 많았다. item01 ~ item35 까지 있었다. 이렇게 되면 한 눈에 클래스를 파악하기도 힘들었다. 설상가상으로, item class 는 entity 였기 때문에 덩달아 service layer 의 코드도 길어졌다.
이런 redundancy 를 줄이기 위해 ITEM01, ITEM02, … 대신에 listOfItems 라는 list 로 대체하는 작업을 했다. 그때 유용하게 사용한 것이 ObjectMapper 의 convertValue 함수다.
먼저 간단한 사용법을 알아보자. 아래와 같이 properties 가 redundant 한 class 는 objectMapper 를 사용해 Map 으로 변환할 수 있다.
class Item(
val someProperty: String,
val item01Name: String,
val item01Value: Int,
val ITEM02Name: String,
val ITEM02Value: Int,
val ITEM03Name: String,
val ITEM03Value: Int
)
fun main() {
val objectMapper = ObjectMapper()
val item = Item("some", "name01", 1, "name02", 2, "name03", 3)
val mappedPropertyInItem = objectMapper.convertValue(item, MutableMap::class.java)
println(mappedPropertyInItem)
}
출력 결과는 아래와 같다.
{someProperty=some, item01Name=name01, item01Value=1, item02Value=2, item03Name=name03, item02Name=name02, item03Value=3}
클래스의 객체의 프로퍼티를 호출하고 싶을 때 objectMapper 를 사용해 간편하게 호출할 수 있다. 주의할 점은, 모든 key 가 lowercase 라는 것이다. 이는 출력 결과에서도 확인할 수 있다.
fun main() {
val objectMapper = ObjectMapper()
val item = Item("some", "name01", 1, "name02", 2, "name03", 3)
val mappedPropertyInItem = objectMapper.convertValue(item, MutableMap::class.java)
println(mappedPropertyInItem["ITEM02Name"])
}
즉, 아래와 같이 null 을 출력한다.
null
이제 구체적인 응용법을 알아보자. 먼저 Item class 를 대체할 NewItem class 를 정의한다.
class NewItem(
val someProperty: String,
val listOfItems: List<ItemMap>
)
class ItemMap(
val itemName: String,
val itemValue: Int
)
이제 objectMapper 를 이용해 Item class object 를 NewItem class object 로 변환하자.
fun main() {
val objectMapper = ObjectMapper()
val item = Item("some", "name01", 1, "name02", 2, "name03", 3)
val mappedPropertyInItem = objectMapper.convertValue(item, MutableMap::class.java)
val listOfItemMaps =
// item01 부터 item03 까지를 표현
(1..3)
.map { number ->
number.toString().padStart(2, '0')
}
.map { numberWithPadding ->
val itemName = mappedPropertyInItem["item${numberWithPadding}Name"].toString()
val itemValue = mappedPropertyInItem["item${numberWithPadding}Value"].toString().toInt()
ItemMap(itemName, itemValue)
}
val newItem = NewItem(item.someProperty, listOfItemMaps)
println(newItem)
}
NewItem(someProperty='some', listOfItems=[ItemMap(itemName='name01', itemValue=1), ItemMap(itemName='name02', itemValue=2), ItemMap(itemName='name03', itemValue=3)])