Я новичок в Котлине и экспериментирую с spring-data-mongodb. См. Пример ниже (также доступен здесь как полностью исполняемый проект Maven с встроенной памятью MongoDb: https://github.com/danielsindahl/spring-boot-kotlin-example ).
Application.kt
package dsitest import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication open class Application fun main(args: Array<String>) { SpringApplication.run(Application::class.java, *args) }
User.kt
package dsitest import org.springframework.data.annotation.Id import org.springframework.data.annotation.PersistenceConstructor import org.springframework.data.mongodb.core.mapping.Document @Document(collection = "user") data class User @PersistenceConstructor constructor(@Id val id: String? = null, val userName: String)
UserRepository.kt
package dsitest import org.springframework.data.repository.CrudRepository interface UserRepository : CrudRepository<User, String>
KotlinIntegrationTest.kt
package dsitest import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner::class) @SpringBootTest class KotlinIntegrationTest constructor () { @Autowired lateinit var userRepository : UserRepository; @Test fun persistenceTest() { val user : User = User(userName = "Mary") val savedUser = userRepository.save(user) val loadedUser = userRepository.findOne(savedUser.id) // Failing code println("loadedUser = ${loadedUser}") } }
При запуске теста KotlinIntegrationTest.persistenceTest я получаю следующее сообщение об ошибке при попытке получить объект User из MongoDb:
org.springframework.data.mapping.model.MappingException: No property null found on entity class dsitest.User to bind constructor parameter to!
Если я изменяю класс данных пользователя, чтобы имя пользователя было равно NULL, все работает.
data class User @PersistenceConstructor constructor(@Id val id: String? = null, val userName: String? = null)
Я хотел бы понять, почему это так, поскольку я не хочу, чтобы имя пользователя было равно NULL. Есть ли альтернатива, лучший способ определить мой класс User в Котлине?
Большое спасибо, Даниэль
Да, это известная проблема. Вы должны проверить, как выглядит байт-код для вашего класса User. Java видит конструктор со всеми присутствующими параметрами и пытается вызвать его с нулевым значением для второго.
Что вы можете сделать, это попробовать добавить @JvmOverloads
к вашему конструктору – это заставит компилятор Kotlin генерировать все версии конструктора, и поэтому Spring Data Mongo может выбрать правильный (избавиться от @PersistenceConstructor).
Вы также можете определить 1 конструктор без параметров по умолчанию – только для фреймворков на основе Java, а второй – с некоторыми стандартными настройками, которые вы используете. Или…
Когда я пишу такие вещи, как вы сейчас, я создаю простые классы данных «persistence» без каких-либо значений по умолчанию, которые отображаются на / из моих обычных объектов домена (своего рода абстракция над базой данных). Вначале это может привести к некоторым накладным расходам, но, тем не менее, поддерживать модель домена не так тесно с моделью хранения, как правило, является хорошей идеей.