java - Kotlin 使用的 Java 库中的泛型和继承

标签 java kotlin generics inheritance

我在实现使用 MockMvc 库中 Java 定义的泛型/接口(interface)类的 Kotlin 类时遇到问题。

库类:

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);

}

我想实现这个(用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);
    }    
}

但是当我尝试在 Kotlin 中重写上述类时,我很难弄清楚应该在 customize 的参数中以及调用 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)
    }
}

在 IntelliJ Idea 中复制粘贴 Java 代码会转换为以下 Kotlin 代码:

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

defaultRequest 下出现错误:

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

当我尝试使用 NothingNothing? 作为 defaultRequest 的通用参数时,我得到运行时 NullPointerException代替方法调用。 defaultRequest方法的实现是:

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;
    }

}

最佳答案

编译器要求显式类型:

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

你可以这样指定:

@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)
    }
}

关于java - Kotlin 使用的 Java 库中的泛型和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63807526/

相关文章:

java - 找不到元素 'persistence' 的声明

android - Playstore 崩溃转储中缺少行号

Java 有界类型

list - 如何在 F# 中将对象强制转换为泛型类型列表

安卓机房 : Each bind variable in the query must have a matching method

c# - 如何将泛型类限制为某些类型(包括 native 数据类型)

java - 如何简化多个字段上空安全比较器的创建?

java - 为什么要运行?

java - Android 内存监控

找不到 Androidx SeekBarPreference xml 属性 setMax