Почему это не перегрузка? - PullRequest
4 голосов
/ 24 апреля 2019

Запись в классе помощника Jooq.(Как только я это выясню, будет добавлено больше специфических для бизнеса методов ...)

import org.jooq.*
import org.springframework.stereotype.Repository
import javax.inject.Inject
import javax.inject.Provider

/**A helper class facilitating database manipulations.
 * Uses jOOQ for its manipulations.
 * Relies on the application context being properly initialized s.t. Spring creates and injects the correct
 * [DSLContext].*/
@Repository
class DatabaseManipulator{

    private val provider: Provider<DSLContext>
    private val create:DSLContext
        get() = provider.get()

    @Inject
    constructor(provider: Provider<DSLContext>) {
        this.provider = provider
    }


    /**Executes non-[Select]-type SQL queries on the database.
     * Does not perform any kind of checks and trusts the client to know what they're doing.
     * @param query the query to be executed.
     *
     * @return depending on the type of the [query]:
     *      <ul>
     *      <li> Delete : the number of deleted records</li>
     *      <li> Insert : the number of inserted records</li>
     *      <li> Merge : result may be meaningless</li>
     *      <li> Truncate : result may be meaningless</li>
     *      <li> Update : the number of updated records</li>
     *      </ul>
     */
    fun execute(query:DSLContext.()-> Query):Int{
        return create.query().execute()
    }

    /**Executes [Select]-type [query] and returns its result*/
    fun <T:Record> execute(query:DSLContext.()->Select<T>):Result<T>{
        return create.query().fetch()
    }
}

Пока все хорошо.Теперь давайте добавим несколько тестов

@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest
@Transactional
class DatabaseManipulatorIT {

    @Inject
    private lateinit var manipulate:DatabaseManipulator

    @Inject
    private lateinit var em:EntityManager

    @Test
    fun executeSelectQuery() {
        //given
        val expectedNumberOfOrganizations = em.createQuery("SELECT COUNT (o) FROM Organization o")
            .singleResult as Long

        //when
        val reportedNumberOfOrganizations = manipulate.execute {
            selectCount().from(ORGANIZATION)
        }.first().value1().toLong()

        //then
        assertThat(reportedNumberOfOrganizations).isEqualTo(expectedNumberOfOrganizations)
    }

    @Test
    fun executeNonSelectQuery() {
        //given
        val expectedNumberOfDeletions = em.createQuery(
            "SELECT COUNT (o) FROM Organization o WHERE o.usageCreditLimited = true"
        ).singleResult as Long

        //when
        val actualNumberOfDeletions = manipulate.execute {(
            deleteFrom(ORGANIZATION)
                .where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
            ) as Query
        }

        //then
        assertThat(actualNumberOfDeletions).isEqualTo(expectedNumberOfDeletions)

    }
}

Не удается скомпилировать, потому что

Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> DeleteConditionStep<OrganizationRecord!>!)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> DeleteConditionStep<OrganizationRecord!>! but DSLContext.() -> Select<???> was expected

Не дерьмо, я не хочу , чтобы вы использовали этот метод, я хочуиспользовать other .

Давайте попробуем сделать это явным:

//when
val actualNumberOfDeletions = manipulate.execute {(
    deleteFrom(ORGANIZATION)
        .where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
    ) as Query
}

все еще не удается скомпилировать второй тестовый пример, потому что

Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> Query)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> Query but DSLContext.() -> Select<???> was expected

Как мне заставить Котлина вызвать правильный метод?

1 Ответ

0 голосов
/ 24 апреля 2019

Select - это, по сути, Query, поэтому метод, который вы хотите использовать, не может быть правильно выведен.

Компилятор разрешает все, что связано с вызовом метода, не обращая внимания на общие ограничениядо самого последнего момента - когда он замечает, что выбранный метод недопустим и завершается с ошибкой.

Эта проблема возникает с generics , компилятор распознает методыкак два разных метода, но при попытке решить метод может не найти правильный метод на основе доступных данных.Если вы хотите узнать, зачем проверять эту статью, Перегрузка и общие ограничения от Jon Skeet.

...