Kotlin casting generic to a data class at runtime

Viewed 116

I am relatively new to Kotlin coming from Java. I have a Jave codebase I am converting to Kotlin.

In my Java Project, I have a BaseModel.java which all my models inherit, the same applies to my Kotlin project except all the models that inherit BaseModel.kt are data classes. I have a Base service that uses Generics that needs to create a copy of my BaseModel.kt Child and set the createdAt field. It is unclear how I can tell Kotlin at runtime that the Child of BaseModel.kt is a data class.

My BaseModel.java which all my models inherit, the model looks like this:

@Getter
@SuperBuilder(toBuilder = true)
@Accessors(fluent = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@NoArgsConstructor
public class BaseModel<ID> {

    @Id
    private ID id;
    @LastModifiedDate
    private LocalDateTime updatedAt;
    @CreatedDate
    private LocalDateTime createdAt;

}

And a Kotlin variant that looks like this:

open class BaseModel(
    @Id open val id: Int,
    open val updatedAt: LocalDateTime,
    open val createdAt: LocalDateTime
)

An example of a child that inherits My kotlin variant

    data class Child(
        val someId: Int,
        override val id: Int,
        override val createdAt: String,
    ) : BaseDto(id, createdAt)

This is my BaseService, here, I am updating the createdAt field using Lombok's Builder, I would like to do the same for my kotlin variant

//V extends BaseModel.java
public Mono<ResponseEntity<?>> update(V v) {
    return getRepository().findById(v.id())
            ...
                val toUpdate = (BaseModel) update
                        .toBuilder()
                        .createdAt(original.createdAt())
                        .build();
                return Mono.just(toUpdate);
            })
     ...
}

Although all the Classes that inherit my kotlin BaseModel are Data classes I cannot seem to find a way to tell Kotlin at runtime that my Child is a Data class so that it can let me access the copy method

//V extends BaseModel.kt
override fun update(v: V): Mono<ResponseEntity<*>> {
    return getRepository().findById(v.id)
        ...
        .flatMap { t ->
           //t.2 extends BaseModel.kt
            val update = t.t2
                Mono.just(update)//I cannot access the copy method even if at runtime all the children that inherit BaseModel are data classes.
        }
        ...
}

Does anyone know how I can achieve this?

1 Answers

I ended up creating the function fun copy(original: T, update: T): T in my BaseService and changed my code to look like this

    override fun update(v: V): Mono<ResponseEntity<*>> {
        return getRepository().findById(v.id)
            ...
            .flatMap { t ->
                  val original = t.t1
                  val update = t.t2
                  Mono.just(copy(original, update))
            }
            ...
    }      

and then in each ChildService I implemented copy like this

override fun copy(original: Match, update: Match): Match {
        return update.copy(updatedAt = original.updatedAt, createdAt = original.createdAt)
}

Sucks and repetitive but it works for now and the only viable solution I have

Related