英文:
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<Submission> block = webClient
.get()
.uri(newSubmissionsUri)
.attributes(clientRegistrationId(CLIENT_REGISTRATION_ID))
.retrieve()
.bodyToMono(new ParameterizedTypeReference<ArrayResponse<Submission>>() {
})
.block();
but this is not working:
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>>() {
};
}
There are no compilation errors. But at runtime, instead of Submission, I'm seeing LinkedHashMap when I debug.
Also tried:
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>>() {
};
}
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>
,其中的T
是java.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<ArrayResponse<Submission>>() {}
you're creating a new subclass that extends ParameterizedTypeReference<ArrayResponse<Submission>>
, 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 <T> ParameterizedTypeReference<ArrayResponse<T>> arrayResponse() {
return new ParameterizedTypeReference<ArrayResponse<T>>() {};
}
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<T>
, with T
being an instance of java.lang.reflect.TypeVariable
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论