我正在使用Sping Boot 应用程序(版本3.2),其中我使用RestClient
类进行外部API调用。我的服务类中的updateProduct
方法调用外部API,并使用invokeAPI
方法返回通用响应。但是,我遇到了一个问题,APIResponseDTO
结果类型没有被正确地推断为ProductDTO
,而是被推断为LinkedHashMap
。
下面是相关代码:
public APIResponseDTO<ProductDTO> updateProduct(@NonNull ProductRequestDTO productRequest) {
return invokeAPI(productRequest, HttpMethod.PUT, ProductDTO.class);
}
public <T, R> APIResponseDTO<T> invokeAPI(R requestDTO, HttpMethod httpMethod, Class<T> responseType) {
Class<?> responseDTOClass = TypeFactory.defaultInstance().constructParametricType(APIResponseDTO.class, responseType).getRawClass();
String productAPI = apiURL + apiVersion + PRODUCTS_API;
HttpHeaders headers = new HttpHeaders();
headers.set("client_id", apiClientId);
headers.set("client_secret", apiClientSecret);
Function<Boolean, String> accessTokenFunction = (forceRefresh) -> fetchAccessTokenResponse(forceRefresh).getAccessToken();
return (APIResponseDTO<T>) restClient.exchange(productAPI,
requestDTO,
httpMethod,
headers,
responseDTOClass,
accessTokenFunction,
GatewayException.class);
}
字符串
以下是相关的DTO:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class APIResponseDTO<T> {
@JsonProperty("status")
private boolean status;
@JsonProperty("errorCode")
private int errorCode;
@JsonProperty("errorMsg")
private String errorMsg;
@JsonProperty("result")
private T result;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductDTO {
@JsonProperty("id")
private String id;
}
型
下面是Restclient
import java.net.URI;
import java.util.Map;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@Slf4j
public class RestClient extends RestTemplate {
public static final String BEARER = "Bearer ";
public static final boolean TOKEN_CACHE_ENABLED = true;
public static final boolean TOKEN_CACHE_DISABLED = false;
private final RetryTemplate retryTemplate;
public <T> ResponseEntity<T> execute(
String uri,
HttpMethod method,
HttpEntity<?> requestEntity,
Class<T> responseType,
Function<Boolean, String> accessTokenFunction) {
ResponseEntity<T> responseEntity =
retryTemplate.execute(retryContext -> super.exchange(uri, method, requestEntity, responseType));
if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// If the response status is 401, retry with a new access token
log.warn("Received 401 response from Salesforce. Retrying with a new access token.");
requestEntity.getHeaders().set(AUTHORIZATION, BEARER + accessTokenFunction.apply(TOKEN_CACHE_DISABLED));
responseEntity = exchange(uri, method, requestEntity, responseType);
}
return responseEntity;
}
public <T, R, E extends RuntimeException> Object exchange(
String apiUrl,
T requestDTO,
HttpMethod httpMethod,
HttpHeaders headers,
Class<?> responseType,
Function<Boolean, String> accessTokenFunction,
Class<E> exceptionClass) {
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set(AUTHORIZATION, BEARER + accessTokenFunction.apply(TOKEN_CACHE_ENABLED));
HttpEntity<T> requestEntity = new HttpEntity<>(requestDTO, headers);
ResponseEntity<?> responseEntity =
execute(apiUrl, httpMethod, requestEntity, responseType, accessTokenFunction);
if (responseEntity != null
&& responseEntity.getStatusCode().value() >= HttpStatus.OK.value()
&& responseEntity.getStatusCode().value() <= HttpStatus.IM_USED.value()) {
return responseEntity.getBody();
} else {
log.error("Failed to fetch the Response: {} for API {} | HttpMethod {} ", responseEntity, apiUrl, httpMethod);
throw new CustomException(exceptionClass,"Failed to fetch the Response: " + responseEntity + " for API " + apiUrl + " | HttpMethod "+ httpMethod);
}
}
}
型
似乎invokeAPI
方法没有正确维护APIResponseDTO
中result
字段的泛型类型信息。它返回的不是预期的ProductDTO
,而是LinkedHashMap
。
x1c 0d1x的数据
我怀疑这个问题可能与TypeFactory.defaultInstance()
的使用有关,但我不知道如何解决它。任何帮助或建议,以解决此类型不匹配问题,将不胜感激。谢谢!
此外,我发现自己在invokeAPI方法中使用了类型转换(APIResponseDTO)。我正在寻找一种更干净的方法来处理这个问题,并避免显式的类型转换。具体来说,是否有一种方法可以修改exchange方法以返回泛型响应而不是Object?
1条答案
按热度按时间b0zn9rqh1#
ParameterizedTypeReference
专门用于涉及集合或具有泛型的自定义对象的响应。这在运行时保留了关键的类型信息,确保了这些参数化类型的准确描述。所以,你可以像这样测试请求:
字符串
这是我测试的调试结果(我需要使用自己的DTO与下游测试API保持一致:
的数据
对于更新的自定义RestClient bean代码,它看起来像这样:
型
您可以使用客户端进行请求,如下所示:(但是,您可以按照自己的方式调整)
型