Универсальный геттер для множественной коллекции в Монго с Kotlin - PullRequest
0 голосов
/ 03 мая 2018

Я использую Kotlin и Mongo (с KMongo ), и у меня есть несколько моделей как UserEntity, MovieEntity и так далее. Каждый из них использует определенный класс Dao для выполнения (фактически) одних и тех же методов. Поэтому я пытаюсь избежать любого дублирования, используя BaseDao, в котором вместо этого должны быть эти методы.

Итак, я передаю конкретную сущность в базовую базу как:

class UserDao : BaseDao<UserEntity>() { ... }

Этот базовый класс реализует обобщенные методы следующим образом:

open class BaseDao<T: Any>() {

    fun get(id: String): T? {
        return getCollection().findOneById(id)
    }

    fun save(entity: T): T {
        return getCollection().save(entity)
    }

    fun delete(id: String) {
        getCollection().deleteOneById(id)
    }
    ...
}

Однако проблема возникает в getCollection() методе:

private inline fun <reified T: Any> getCollection(): MongoCollection<T> {
    return MongoDb.getDatabase().getCollection<T>()
}

Это вызывает ошибку компиляции каждый раз, когда я ее называю:

Type inference failed: Not enough information to infer parameter T in 
inline fun <reified T : Any> getCollection(): MongoCollection<T#1 (type parameter of app.api.db.dao.BaseDao.getCollection)>  
Please specify it explicitly.

Я не могу найти правильный способ сделать это. Я уже проверил эти потоки, но не заставил его работать: Использование универсального типа класса в Kotlin & Абстрактный класс Kotlin с универсальным параметром и методами, которые используют тип param .

Вопрос:

Как мне получить этот универсальный BaseDao, который должен получать любую коллекцию каждого ребенка Dao?

Ответы [ 2 ]

0 голосов
/ 16 июня 2018

Решение состоит в том, чтобы использовать отражение в качестве упомянутого Зигзаго с помощью KMongoUtil:

protected fun getCollection(): MongoCollection<T> =
    getDaoEntityClass().let { k ->
        MongoDb.getDatabase().getCollection(
            KMongoUtil.defaultCollectionName(k), k.java)
    }

@Suppress("UNCHECKED_CAST")
private fun getDaoEntityClass(): KClass<T>
    = ((this::class.java.genericSuperclass
        as ParameterizedType).actualTypeArguments[0] as Class<T>).kotlin
0 голосов
/ 03 мая 2018

JVM забывает тип универсального T в BaseDao<T: Any>() во время выполнения, поэтому вывод типа завершается неудачно. Решением этой проблемы может быть передача класса KC в T в конструкторе BaseDao:

open class BaseDao<T: Any>(val kClass: KClass<T>) {
    ...
}

После этого передайте своей функции reified аргумент, который принимает `KClass:

private inline fun <reified T: Any> getCollection(val kClass: KClass<T>):  MongoCollection<T> {
    return MongoDb.getDatabase().getCollection<T>()
}

Я не знаю, как сделать это, не передавая KClass в качестве аргумента функции, но это должно сработать, так как универсальный T может быть получен из предоставленного kClass. `

Другим способом было бы сделать все методы встроенной функции BaseDao с улучшенными обобщениями и сбросить обобщение в классе.

open class BaseDao() {

    inline fun <reified T: Any> get(id: String): T? {
        return getCollection().findOneById(id)
    }

    inline fun <reified T: Any> save (entity: T): T {
        return getCollection().save(entity)
    }

    inline fun <reified T: Any> delete(id: String) {
        getCollection().deleteOneById(id)
    }
    ...
}

Таким образом, обобщенный T может быть получен, так как метод, вызывающий getCollection, также является усовершенствованным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...