Generics and inheritance in Java library used from Kotlin

痴心易碎 提交于 2021-02-07 10:25:44

问题


I'm having problem implementing a Kotlin class which uses Java-defined generics/interfaces classes from MockMvc library.

Library classes:

public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder<B>> extends MockMvcBuilder {

    // ...

    <T extends B> T defaultRequest(RequestBuilder requestBuilder);

    // ...

}

@FunctionalInterface
public interface MockMvcBuilderCustomizer {

    /**
     * Customize the given {@code builder}.
     * @param builder the builder
     */
    void customize(ConfigurableMockMvcBuilder<?> builder);

}

I would like to implement this (in Java) :

@Component
public class ApiKeyHeaderMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {

    @Override
    public void customize(ConfigurableMockMvcBuilder<?> builder) {
        RequestBuilder apiKeyRequestBuilder = MockMvcRequestBuilders.get("any")
            .header("api-key-header", "apikeyvalue");
        builder.defaultRequest(apiKeyRequestBuilder);
    }    
}

But when I try to rewrite the above class in Kotlin, I'm having troubles figuring out what generic constraint I should use both in customize's parameter and when calling builder.defaultRequest

@Component
class ApiKeyHeaderMockMvcBuilderCustomizer : MockMvcBuilderCustomizer {
    // is this generic right?
    override fun customize(builder: ConfigurableMockMvcBuilder<*>) { 
        val apiKeyRequestBuilder: RequestBuilder =
            MockMvcRequestBuilders.get("http://any")
                .header("api-key-header", "apikeyvalue")

        // won't compile, using Nothing compiles but fails at runtime
        builder.defaultRequest<*>(apiKeyRequestBuilder)
    }
}

Copy-pasting the code from Java in IntelliJ Idea converts to this Kotlin code :

@Component
class ApiKeyHeaderMockMvcBuilderCustomizer : MockMvcBuilderCustomizer {
    override fun customize(builder: ConfigurableMockMvcBuilder<*>) {
        val apiKeyRequestBuilder: RequestBuilder = MockMvcRequestBuilders.get("any")
            .header("api-key-header", "apikeyvalue")
        builder.defaultRequest(apiKeyRequestBuilder)
    }
}

With error under defaultRequest :

Type inference failed: Not enough information to infer parameter T in 
fun <T : Nothing!> defaultRequest(requestBuilder: RequestBuilder) : T
Please specify it explicitly.

When I try using Nothing or Nothing? in as generic parameter for defaultRequest, I get runtime NullPointerException in place of the method call. The implementation of the defaultRequest method is :

public abstract class AbstractMockMvcBuilder<B extends AbstractMockMvcBuilder<B>>
        extends MockMvcBuilderSupport implements ConfigurableMockMvcBuilder<B> {

    @Override
    public final <T extends B> T defaultRequest(RequestBuilder requestBuilder) {
        this.defaultRequestBuilder = requestBuilder;
        return self();
    }

    @SuppressWarnings("unchecked")
    protected <T extends B> T self() {
        return (T) this;
    }

}

回答1:


the compiler asks for the explicit type:

Type inference failed: Not enough information to infer parameter T in 
fun <T : Nothing!> defaultRequest(requestBuilder: RequestBuilder) : T
Please specify it explicitly.

you can specify it like this:

@Component
class ApiKeyHeaderMockMvcBuilderCustomizer<T :Nothing?> : MockMvcBuilderCustomizer {
    override fun customize(builder: ConfigurableMockMvcBuilder<*>) {
        val apiKeyRequestBuilder: RequestBuilder = MockMvcRequestBuilders.get("any")
            .header("api-key-header", "apikeyvalue")
        builder.defaultRequest<T>(apiKeyRequestBuilder)
    }
}


来源:https://stackoverflow.com/questions/63807526/generics-and-inheritance-in-java-library-used-from-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!