Search code examples
kotlinkotlin-exposed

How to re-use DAO class of Exposed for JSON serialization or transfering data?


Recently I try to learn Kotlin by writing a Kotlin + Exposed demo.

Common steps using Java + MyBatis would be: creating Java Bean class, mapper class, service class and service implementation class

@Data class UserBean { String username; String password; }
@Mapper interface UserMapper extends BaseMapper<UserBean> {}
interface UserService extends BaseService<UserBean> {}
@Service UserSerivceImpl extends BaseServiceImpl<UserBean> implements UserService {}

Then those Java Bean classes are used in any other parts of system for database IO and JSON serialization.

// create instance and convert to JSON
var user = new UserBean();
user.setUsername("username");
user.setPassword("password");
var om = new ObjectMapper();
var json = om.valueToTree(user);

Following official doc of Exposed DAO API, I create those classes:

class User(id : EntityID<Int>) : IntEntity(id)
{
    companion object : IntEntityClass<User>(Users)
    var username by Users.username
    var password by Users.password
}
object Users : IntIdTable()
{
    val username = varchar("username", 64)
    val password = varchar("password", 64)
}

When performing database IO, User.all() and User.new { } api work well. But creating instance directly would throw an exception:

// get data from JSON or somewhere else
val username = ...
val password = ...
// trying to create instance
val id = EntityID(-1, User.table) // trying to create an empty ID. I don't know if this is allowed
val user = User(id)
user.username = username // this would throw exception
user.password = password
Caused by: java.lang.IllegalStateException: Property klass should be initialized before get.
    at kotlin.properties.NotNullVar.getValue(Delegates.kt:62)
    at org.jetbrains.exposed.dao.Entity.getKlass(Entity.kt:34)
    at org.jetbrains.exposed.dao.Entity.setValue(Entity.kt:198)

Post here says Exposed does not allow creating DAO objects by yourself. So is there a easy way to re-use those DAO classes for JSON serialization or transfering data between parts of program? Should I create a DTO class with identical data fields?


Solution

  • Exposed Entities are stateful objects. You shouldn't serialize them directly. Instead, as you mentioned, you should use a simple data class with serialization annotations relevant to you.

    For example:

    class User(id : EntityID<Int>) : IntEntity(id)
    {
        companion object : IntEntityClass<User>(Users)
        var username by Users.username
        var password by Users.password
    
        fun asResponse(): UserResponse {
            return UserResponse(username, password)
        }
    }
    
    @Serializable
    data class UserResponse(val username: String, val password: String)