Generics and inheritance in Java library used from Kotlin

huangapple go评论69阅读模式
英文:

Generics and inheritance in Java library used from Kotlin

问题

I understand that you want a translation of the code without the code part itself. Here's the translated explanation:

问题描述:
我在实现一个使用MockMvc库中的Java定义的泛型/接口类的Kotlin类时遇到问题。

库中的类:

public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder<B>> extends MockMvcBuilder {
    // ...
    <T extends B> T defaultRequest(RequestBuilder requestBuilder);
    // ...
}

@FunctionalInterface
public interface MockMvcBuilderCustomizer {
    /**
     * 自定义给定的{@code builder}。
     * @param builder builder
     */
    void customize(ConfigurableMockMvcBuilder<?> builder);
}

我想要在Java中实现这个(在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 {
    // 是否正确使用了泛型?
    override fun customize(builder: ConfigurableMockMvcBuilder<*>) { 
        val apiKeyRequestBuilder: RequestBuilder =
            MockMvcRequestBuilders.get("http://any")
                .header("api-key-header", "apikeyvalue")

        // 不会编译,使用Nothing编译通过但在运行时失败
        builder.defaultRequest<*>(apiKeyRequestBuilder)
    }
}

从IntelliJ Idea中复制代码到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下有错误:

类型推断失败:无法从`fun <T : Nothing!> defaultRequest(requestBuilder: RequestBuilder) : T`中推断出参数T的足够信息
请明确指定它。

当我尝试在defaultRequest的泛型参数中使用NothingNothing?时,在方法调用处得到运行时的NullPointerExceptiondefaultRequest方法的实现如下:

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

请注意,Kotlin中的泛型参数和Java中的泛型参数之间可能存在一些差异,这可能导致类型推断失败和运行时错误。您可能需要查看MockMvc库的文档或寻求更多帮助以解决此问题。

英文:

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

Library classes:

public interface ConfigurableMockMvcBuilder&lt;B extends ConfigurableMockMvcBuilder&lt;B&gt;&gt; extends MockMvcBuilder {

    // ...

    &lt;T extends B&gt; T defaultRequest(RequestBuilder requestBuilder);

    // ...

}

@FunctionalInterface
public interface MockMvcBuilderCustomizer {

	/**
	 * Customize the given {@code builder}.
	 * @param builder the builder
	 */
	void customize(ConfigurableMockMvcBuilder&lt;?&gt; builder);

}

I would like to implement this (in Java) :

@Component
public class ApiKeyHeaderMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {

    @Override
    public void customize(ConfigurableMockMvcBuilder&lt;?&gt; builder) {
        RequestBuilder apiKeyRequestBuilder = MockMvcRequestBuilders.get(&quot;any&quot;)
            .header(&quot;api-key-header&quot;, &quot;apikeyvalue&quot;);
        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&lt;*&gt;) { 
        val apiKeyRequestBuilder: RequestBuilder =
            MockMvcRequestBuilders.get(&quot;http://any&quot;)
                .header(&quot;api-key-header&quot;, &quot;apikeyvalue&quot;)

        // won&#39;t compile, using Nothing compiles but fails at runtime
        builder.defaultRequest&lt;*&gt;(apiKeyRequestBuilder)
    }
}

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

@Component
class ApiKeyHeaderMockMvcBuilderCustomizer : MockMvcBuilderCustomizer {
    override fun customize(builder: ConfigurableMockMvcBuilder&lt;*&gt;) {
        val apiKeyRequestBuilder: RequestBuilder = MockMvcRequestBuilders.get(&quot;any&quot;)
            .header(&quot;api-key-header&quot;, &quot;apikeyvalue&quot;)
        builder.defaultRequest(apiKeyRequestBuilder)
    }
}

With error under defaultRequest :

Type inference failed: Not enough information to infer parameter T in 
fun &lt;T : Nothing!&gt; 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&lt;B extends AbstractMockMvcBuilder&lt;B&gt;&gt;
		extends MockMvcBuilderSupport implements ConfigurableMockMvcBuilder&lt;B&gt; {

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

	@SuppressWarnings(&quot;unchecked&quot;)
	protected &lt;T extends B&gt; T self() {
		return (T) this;
	}

}

答案1

得分: 2

以下是翻译好的内容:

编译器要求明确的类型:

类型推断失败在函数fun <T : Nothing!> defaultRequest(requestBuilder: RequestBuilder) : T中没有足够的信息来推断参数T请明确指定它

您可以像这样指定它:

@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)
    }
}
英文:

the compiler asks for the explicit type:

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

you can specify it like this:

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

huangapple
  • 本文由 发表于 2020年9月9日 16:18:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63807526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定