Hi, I'm new to Kotlin. I have a Spring Boot applic...
# server
g
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:
Copy code
//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
This would be a good place to use an extension function: https://kotlinlang.org/docs/reference/extensions.html
2
n
why do you use a DTO in the first place?
g
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
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
for DTOs I make mappers or use http://modelmapper.org/ in Java but I don't know how it will work with Kotlin 🙂
n
whatever the tool why would use add a conversion layer from entity to dto?
a
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
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
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
@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
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.
Copy code
@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(...)
}