I'm trying to write a generic function to do some Webflux operations and I'm getting a class cast exception that I can't figure out
* @param <T> Type of the contract
* @param <U> Return type of this method
* @param <V> Return type from the service
public <T, U, V> U sendRequest(String url, T contract, Function<V, U> transform) {
ParameterizedTypeReference<T> contractType = new ParameterizedTypeReference<T>() {};
ParameterizedTypeReference<V> returnType = new ParameterizedTypeReference<V>() {};
final WebClient.ResponseSpec foo = webClient.post()
.uri(url)
.body(Mono.just(contract), contractType)
.retrieve();
Mono<V> mono = foo.bodyToMono(returnType);
final Mono<U> trans = mono.map(m -> transform.apply(m));
return trans.block();
}
This code works fine in its non-generic form. But when I call this generic method with something like this
requestRunner.<Contract, String, ViewModel>sendRequest(url, contract, v->(String)v.getResult().get("outputString"));
I get an exception:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.torchai.service.common.ui.ViewModel
at com.torchai.service.orchestration.service.RequestRunner.lambda$sendRequest$0(RequestRunner.java:44)
I'm running version 2.4.5 of SpringBoot, so I don't believe this applies:https://github.com/spring-projects/spring-framework/issues/20574
Just for a little more context, in the example above, ViewModel (generic type <V>
) is the format that the service returns its data. I'm then extracting just the piece I need, in this case a string (generic type <U>
) The lambda function that is passed in gets the relevant string from the Response. But for some reason, the Mono is not being mapped properly to ViewModel. If I take out the map() and just return the ViewModel, it appears to work.
Again, if I do this in a non-generic way, it works fine. I can do the map() step and it properly returns a String
UPDATE
Just want to make it clear that this works fine with a non generic version like this:
public String sendRequest(String url, Contract contract, Function<ViewModel, String> transform) {
ParameterizedTypeReference<Contract> contractType = new ParameterizedTypeReference<Contract>() {};
ParameterizedTypeReference<ViewModel> returnType = new ParameterizedTypeReference<ViewModel>() {};
final WebClient.ResponseSpec foo = webClient.post()
.uri(url)
.body(Mono.just(contract), contractType)
.retrieve();
Mono<ViewModel> mono = foo.bodyToMono(returnType);
final Mono<String> trans = mono.map(m -> transform.apply(m));
return trans.block();
}
It is called this way
requestRunner.<Contract, String, ViewModel>sendRequest(textExtractorUrl, cloudContract, v -> (String) v.getResult().get("outputString"));
It correctly returns a string, which is exactly what I wanted from the generic version