https://kotlinlang.org logo
Title
g

Gokul

07/23/2018, 5:51 AM
Hi, I'm new to Kotlin. I have a Spring Boot application currently written in Java, We are writing new APIS's in Kotlin. I have a question regarding handling
Entity to DTO conversion
. I created a
data class
for the
entity
and added a
toDto
method on it. But here the
Entity
is aware of the DTO, which isn't really required for the entity. It works fine. But I am not sure if this is the right way of doing it? Any thoughts? 🙏 A simpler version of my code is:
//Person DTO

data class PersonDto (
	val name: String
)

//Person Entity

@Entity
@Table(name = "persons")
data class Person(
@Id
val id: Integer,

@Column
val firstName: String,

@Column
val lastName: String
)

{
    internal fun toDto(): PersonDto = PersonDto(
            name = "${this.firstName}  ${this.lastName}"
    )

}
d

dave

07/23/2018, 7:16 AM
This would be a good place to use an extension function: https://kotlinlang.org/docs/reference/extensions.html
2
n

nfrankel

07/23/2018, 7:23 AM
why do you use a DTO in the first place?
g

Gokul

07/23/2018, 11:52 AM
I am new to Kotlin on the server and was following this tutorial: https://blog.codecentric.de/en/2017/06/kotlin-spring-working-jpa-data-classes/
n

nfrankel

07/23/2018, 12:25 PM
dto have nothing to do with kotlin the question is why do you use dto? in java, my question would be the same what benefit(s) do the dto offer? over plainly sending the entities (or their projections) to the display layer
t

Todor Atanasov

07/23/2018, 12:39 PM
for DTOs I make mappers or use http://modelmapper.org/ in Java but I don't know how it will work with Kotlin 🙂
n

nfrankel

07/23/2018, 12:43 PM
whatever the tool why would use add a conversion layer from entity to dto?
a

andyb

07/23/2018, 1:57 PM
In many services, the domain model exposed via the REST interface only exposes a subset of the properties in the underlying database entity. In my experience it’s not great practice to expose the database entities directly to the consuming services hence the need for DTOs.
👍 6
I have a particular aversion to the @RepositoryRestResource annotation which sends shivers down my spine.
t

Todor Atanasov

07/23/2018, 2:07 PM
If you have business layer and data layer for example you would not like your data layer to use model from your business layer. Same for presentation layer. With DTOs you are making more classes and maybe rising the complexity but you can achieve layer separation as a result so it really is a trade off. In my opinion ! in most cases it is preferable to achieve the separation.
👍 2
n

nfrankel

07/23/2018, 2:14 PM
i beg to disagree most of the time, dto usage is a sign of overengineering
and when you want to add a language it just adds more noise
by default (especially if you use spring boot) you can defer that responsibility to the jackson converter
g

Gokul

07/23/2018, 11:58 PM
@nfrankel I am using DTOs to offload the complex validations from the entity. I prefer having
thin models
.
@Todor Atanasov Thanks for the pointer. But http://modelmapper.org/ does not support Kotlin yet. However I did come across http://mapstruct.org/ . It seems promising and it has better support for Kotlin out of the box. Here is an illustration: https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-kotlin
👍 1
d

dmulligan

07/25/2018, 4:29 PM
I have used Dozer in the distant past, and there appear to be a number of newer options now. I did find this which maybe of interest. https://github.com/arey/java-object-mapper-benchmark
In my current project, we have hard coded the mappings in a very similar way to what you have in your example. In addition we have constructors in the entity model that take the DTO when saving back to the database. But we did run into a number of issues. 1) Lazy lists were getting fetched which didn’t need to be fetched. For instance, we have a
User
, which has a list of previous passwords. This
User
is used in may other classed to track who created or updated that object. As a result, whenever we transfer those other objects over and back between DTOs we need to populate the lazy password history. We got around this by creating a
UserSummary
, but it was still not ideal. 2) Parent child relationships were never simple. We got around this used
init
blocks like before, but again I was never happy with them as any simple update to the user would result in the password history getting fetched from the database.
@Entity(name = "users")
data class User(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: PersistanceId = -1,

    @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true)
    @OrderBy("id DESC")
    val passwordHistory: List<Password> = mutableListOf(),
) {

    constructor(
        user: User,
        passwordHistory: List<PersistedPassword>,
    ) : this(  ... )

    init {
        passwordHistory.forEach { it.user = this }
    }

    fun toUserDto() = UserDto(...)
}