It's incredible that it doesn't work. Is it a bug or a feature that nobody have implemented in Spring Framework?
It's the base of Generics principle (Below, I propose a solution to solve it after creation object you have the type so inject after construction object Type as private and final in object as Class).
I have a generics class where S is a request body and T is response body of a webclient in a reactive mode get new Bearer Token or return latest token, if it doens't expried, and calling server by that token without using .block*() methods in no blocking mode.
In my class I need to use my class which is Client and a method return T type responsebody and pass requestbody parameter as S type but using T in below and it doesn't work:
public Mono<T> getResponse( @NotBlank String logHash,
@NotBlank String url,
@NotNull @NotBlank @NotEmpty S requestBody,
@NotNull @NotBlank @NotEmpty Class<T> responseBodyClass) {
return getToken()
.flatMap(token ->
webClient
.post()
.uri(url)
.header("Authorization", "Bearer " + token)
.body(BodyInserters.fromValue(requestBody))
.retrieve()
.onStatus(HttpStatus.INTERNAL_SERVER_ERROR::equals, response -> response.bodyToMono(String.class).map(Exception::new))
.onStatus(HttpStatus.BAD_REQUEST::equals, response -> response.bodyToMono(String.class).map(Exception::new))
THE PROBLEM ! ========> .bodyToMono(new ParameterizedTypeReference<T>() {})
.doOnSuccess(response -> log.debug("{} full url {} response {}", logHash, this.serverUrl + url, response))
.doOnError(ex -> {
log.error("{} {}", logHash, ex.getMessage());
ex.printStackTrace();
})
)
.doOnSuccess(token -> log.debug("{} url {} response {}", logHash, this.serverUrl + url, token))
.doOnError(ex -> {
log.error("{} {}", logHash, ex.getMessage());
ex.printStackTrace();
});
.bodyToMono(new ParameterizedTypeReference<T>() {})
with responseBody Class Type which is a .class of my responseBody to avoid exception because JVM can't find T type for return body object:
.bodyToMono(responseBody)
What type of Generics Type is this implementatio?I autowire class I pass Type in autowiring how is possibile that this can't find Type?
new ParameterizedTypeReference<T>() {}
caller without use @Autowired as best practices:
private Client<CheckCustomerBody, ApimResponse> client = null;
And in method that use client it I need to passawhen call it
client = new Client<CheckCustomerBody, ApimResponse>();
client.configure( WebClient.builder(),
ClientType.XXXX_XX,
channelEnum,
logHash,
Optional.empty(),
Optional.empty(),
Optional.empty()
);
return client
.getResponse( logHash,
WebOrderConstants.API_EXT_CHECK,
request,
ApimResponse.class)
.map(apimResponse -> validationProductChange(
apimResponse.getResponse(),
customer.getClientAccountCode(),
logHash
)
? "OK"
: "KO"
)
.doOnError(ex -> {
log.error("{} END {} : Error using d365 service", logHash, prefix);
ex.printStackTrace();
});
Thanks a lot for your reply, I searched a different solution but I can't find it and I don't know why this is normal in AOP of Spring, have Type in Generics class can find a lot of exceptions.
Please analyze this scenario but in general will be very usefull allow to inject by Spring Framework AOP the type of Generics when object is created to analyze in runtime if there are errors and without add type strictly in class.
Spring Team can use the same logic of @Value used for application.properties but in runtime you have Type when istantiate the class or using @PostConstruct.
Comment From: skyblackhawk
Comment From: sdeleuze
Please provide a minimal reproducer as an attached project or a link to a repository with a test that allow to reproduce the error and a as concise and focused formulation of you question and/or expected behavior.
Comment From: skyblackhawk
Ok, it depends on the kind of type erasure in Generics for backwards compatibility with the 20 year old JVM. Community don't ask the JVM team why they can't think that via the configuration on the JVM it is possible to specify a new parameter when Java is in runtime that links Types used in Generics only adding in runtime specific metadata class to original class Generics metadata and inject that type in that object in realtime, so that of the real object have type in the post construct by AOP AspectJ for example? Java continue to ensure backwards compatibility checks at compile time whether the code allows this new mode, i.e. the generics continue to work as before or add an olderVersions parameter, for example to work in type erasure mode or with types in generics by a parameter. So that JVM will haven't heap pollution and support the right type in class in compilation and execution with a Generics class, metadata class added and verify in compile and runtime that's all correct by type without pass parameter to return from a method if it must used in Generic method for example Jackson in my example. If olderVersion parameter is enabled remove follow mechanism and for default support it: - that add in runtime metadata Class in memory and - add after post construct the return type Class
that is the problem in Generics to specify by an adder parameter Class<>.
I know that Generics = Object but in a method of Generics you need to know what real type using because it can be passed to another class method that need to know how map data in it as Jackson.
I know now for what reason you reply me in that mode ;)
Comment From: sdeleuze
Please pay attention to my ask in https://github.com/spring-projects/spring-framework/issues/34583#issuecomment-2720542619, and provide a minimal reproducer as an attached project or a link to a repository.
Comment From: skyblackhawk
I close it without JDK Community that change eraser type no solution can be found...
Please read previous comment I replied alone finding the problem.
Only collections based on a object can use new ParameterizedTypeReference
Because Generics are managed as Object and without Class metadata you can't do nothing. It exists for JDK backward compatibility to first version.
So if JDK community not implement a solution by a flag on JDK JRE no solution can be found, the smart solution by AspectJ 1.9.23 for Java23 or Spring Framework 6 AOP can't be followed.