为什么不超载?

时间:2019-04-24 11:31:44

标签: java kotlin overloading type-inference overload-resolution

在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

不,我不希望您使用该方法,我希望您使用其他

让我们尝试使其明确:

//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

如何让Kotlin调用正确的方法?

1 个答案:

答案 0 :(得分:0)

hello\nworld 本质上是Select,因此无法正确推断要使用的方法。

  

编译器解决了有关方法调用的所有问题,直到最后一刻都没有关注任何涉及到的泛型约束,因为它注意到所选方法无效,并失败并显示错误。

泛型会出现此问题,编译器将方法识别为两种不同的方法,但是当尝试解析该方法时,它可能无法根据可用数据找到正确的方法。如果您想知道为什么要查看本文,请参阅Jon Skeet的Overloading and Generic constraints