javakotlingenericshibernate-search

How to fix the generics error in Koltin when using hibernate search DSL


The following java code works fine in java:

import org.hibernate.search.engine.search.predicate.dsl.MatchPredicateOptionsStep
import org.hibernate.search.engine.search.predicate.dsl.SearchPredicateFactory
import org.hibernate.search.engine.search.query.SearchResult
import org.hibernate.search.mapper.orm.Search
import org.springframework.data.domain.Pageable
// ...... omit

    SearchSession searchSession = Search.session(entityManager);
    SearchResult<MediaAsset> hits = searchSession.search(MediaAsset.class)
            .where(f -> f.match().field("tag").matching(tagName))
            .fetch(offset, pageable.getPageSize());

however if I convert it to kotlin, it can't resolve the generics.

// below SearchResult can only resolve to 'out Any' not MediaAsset class
val hits: SearchResult<out Any> = searchSession.search(MediaAsset::class.java)
            .where { f: SearchPredicateFactory -> f.match().field("tag").matching(tagName) }
            .fetch(offset, pageable.pageSize)

IntelliJ Java to Kotlin auto conversion also gives this result. How do I fix the generics?


Solution

  • Take this with a grain of salt as I don't use Kotlin at all, but from what I can see Kotlin doesn't manage to resolve the first generic argument of the return type of search, so your workaround would be to cast the result of search:

    val hits: SearchResult<MediaAsset> = (searchSession.search(MediaAsset::class.java)
                    as SearchQuerySelectStep<out SearchQueryOptionsStep<*, MyKotlinEntity, *, *, *>, MyKotlinEntity, *, *, *, *>)
                .where { f: SearchPredicateFactory -> f.match().field("tag").matching(tagName) }
                .fetch(offset, pageable.pageSize)
    

    Yes it's ugly, but then it's a workaround for what appears to be a limitation of Kotlin's handling of generics for Java interfaces ¯\_(ツ)_/¯ . Funny when Kotlin is arguably much better with generics in other areas...

    Other people have been hit by this before, e.g. the people presenting here (in French) mention it briefly, but I don't think they provide a solution.

    If you have suggestions to make the DSL work better with Kotlin, without breaking backwards compatibility for Java, I'd be glad to hear them. E.g. maybe Kotlin supports some kind of extension methods that would override the Java definition and allow us to get the Kotlin compiler to behave similarly to Java's? I really don't know...

    EDIT: FWIW I created https://hibernate.atlassian.net/browse/HSEARCH-5003, but so far I don't have any clue how to improve things, so... ideas are welcome :)