参数化类型引用在以泛型形式调用时返回 LinkedHashMap。

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

ParameterizedTypeReference returning LinkedHashMap when called as function with generics

问题

只是对使用类型参数化TypeParameterizedTypeReference时的行为有些好奇

这段是有效的

    ArrayResponse<Submission> block = webClient
                    .get()
                    .uri(newSubmissionsUri)
                    .attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<ArrayResponse<Submission>>() {
                    })
                    .block();

但是这段是无效的

    ArrayResponse<Submission> block2 = webClient
                    .get()
                    .uri(newSubmissionsUri)
                    .attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
                    .retrieve()
                    .bodyToMono(arrayResponse(Submission.class))
                    .block();

    private <T> ParameterizedTypeReference<ArrayResponse<T>> arrayResponse(Class<T> clz) {
        return new ParameterizedTypeReference<ArrayResponse<T>>() {
        };
    }

没有编译错误但在运行时调试时我看到的不是 Submission而是 LinkedHashMap

还尝试了

    ArrayResponse<Submission> block2 = webClient
                    .get()
                    .uri(newSubmissionsUri)
                    .attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
                    .retrieve()
                    .bodyToMono(this.<Submission>arrayResponse())
                    .block();

    private <T> ParameterizedTypeReference<ArrayResponse<T>> arrayResponse() {
        return new ParameterizedTypeReference<ArrayResponse<T>>() {
        };
    }

但再次看到的是 LinkedHashMap
英文:

Just curious about this behavior when using Type ParameterizedTypeReference

This is working

ArrayResponse&lt;Submission&gt; block = webClient
.get()
.uri(newSubmissionsUri)
.attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
.retrieve()
.bodyToMono(new ParameterizedTypeReference&lt;ArrayResponse&lt;Submission&gt;&gt;() {
})
.block();

but this is not working:

ArrayResponse&lt;Submission&gt; block2 = webClient
.get()
.uri(newSubmissionsUri)
.attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
.retrieve()
.bodyToMono(arrayResponse(Submission.class))
.block();
private &lt;T&gt; ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt; arrayResponse(Class&lt;T&gt; clz) {
return new ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt;() {
};
}

There are no compilation errors. But at runtime, instead of Submission, I'm seeing LinkedHashMap when I debug.

Also tried:

ArrayResponse&lt;Submission&gt; block2 = webClient
.get()
.uri(newSubmissionsUri)
.attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
.retrieve()
.bodyToMono(this.&lt;Submission&gt;arrayResponse())
.block();
private &lt;T&gt; ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt; arrayResponse() {
return new ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt;() {
};
}

but again seeing LinkedHashMap

答案1

得分: 4

通常在Java中使用泛型时,答案与类型擦除(Type Erasure)有关。

由于类型擦除,你不能直接从类本身获取泛型类型信息,但可以从父类获取。这就是为什么Spring和Jackson需要依赖于Class.getGenericSuperclass()来获取有关泛型类型的信息。当你执行以下操作时:

new ParameterizedTypeReference<ArrayResponse<Submission>>() {}

你创建了一个扩展了ParameterizedTypeReference<ArrayResponse<Submission>>的新子类,Spring可以使用它从其getGenericSuperclass方法中获取类型参数。然而,要注意一个重要的事情:类型在编译时已知,并且无法更改。它现在真正成为类的一部分。

另一方面,当你尝试执行以下操作时:

private <T> ParameterizedTypeReference<ArrayResponse<T>> arrayResponse() {
    return new ParameterizedTypeReference<ArrayResponse<T>>() {};
}

编译器不会真正用类型替换T,因为该方法可能在任何地方以任何类型调用。现在,这个T也成为了ParameterizedTypeReference子类的一部分。

如果你调用这个方法(因此向ParameterizedTypeReference提供了实际类型),getGenericSuperclass的结果仍将包含ArrayResponse<T>,其中的Tjava.lang.reflect.TypeVariable的一个实例。

英文:

As very often with generics in java, the answer is related to the type erasure.

Because of the erasure, you can't just get the generic type information from the class itself, but it's possible to get it from a parent class. That's why Spring and Jackson have to rely on Class.getGenericSuperclass() to get the information about your generic type. When you do

new ParameterizedTypeReference&lt;ArrayResponse&lt;Submission&gt;&gt;() {}

you're creating a new subclass that extends ParameterizedTypeReference&lt;ArrayResponse&lt;Submission&gt;&gt;, and Spring can use it to get the type parameter from its getGenericSuperclass. However, note an important thing: the type is known at compile time, and can't change. It's now really a part of the class.

On the other hand, when you try to do

private &lt;T&gt; ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt; arrayResponse() {
return new ParameterizedTypeReference&lt;ArrayResponse&lt;T&gt;&gt;() {};
}

the compiler doesn't really substitute T with the type, because the method might have been called in any place and with any type. This T now also becomes a part of the ParameterizedTypeReference subclass.

If you call this method (thus, providing the actual type to ParameterizedTypeReference) the result of getGenericSuperclass will still contain ArrayResponse&lt;T&gt;, with T being an instance of java.lang.reflect.TypeVariable.

huangapple
  • 本文由 发表于 2020年10月12日 23:19:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/64320631.html
匿名

发表评论

匿名网友

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

确定