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?
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)