Search code examples
javaspringexceptionresttemplate

Spring RestTemplate exchange throws UnhandledHttpStatusException


Overview: I am going to use RestTemplate to invoke a get request from external REST webservice.

My code is as follows:

@Slf4j
@Component("AccMemberDetailsApiControllerImpl")
public class AccMemberDetailsApiControllerImpl implements MemberDetailsApiController {

    private static final String CONTENT_TYPE_HEADER_NAME = "Content-Type";
    private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
    private static final String USERID_PARAMETER_NAME = "userId";
    private static final String VEHICLEID_PARAMETER_NAME = "vehicleId";

    private static final ObjectMapper mapper = new ObjectMapper();

    /**
     * This constant is used to check whether or not the response from ACC is an empty JSON string
     */
    private static final String EMPTY_RESPONSE = "{}";

    @Value("${com.blss.memberServices.provider.posServiceURL}")
    private String accPosServiceURL;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AccTokenUtility accTokenUtility;

    @Autowired
    private ResourceMessage resourceMessage;

    void setAccTokenUtility(AccTokenUtility accTokenUtility) {
        this.accTokenUtility = accTokenUtility;
    }

    void setResourceMessage(ResourceMessage resourceMessage) {
        this.resourceMessage = resourceMessage;
    }

    /**
     * @see MemberDetailsApiController#getMemberDetails(String, String)
     */
    @Override
    public MemberDetailsModel getMemberDetails(String storeId, String membershipIdentifier) {

        /**
         * Getting CAD token
         */
        String token = accTokenUtility.getCadToken();

        /**
         * Preparing the request
         */
        HttpHeaders headers = new HttpHeaders();

//        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        headers.set(CONTENT_TYPE_HEADER_NAME, MediaType.APPLICATION_JSON_VALUE);
        headers.set(AUTHORIZATION_HEADER_NAME, token);
        HttpEntity<String> entity = new HttpEntity<>(headers);

        /**
         * Creating the dispatch URL by means of userId and vehicleId
         */
        String dispatchURL = accPosServiceURL + "DispatchedEvent/{userId}/{vehicleId}";

        /**
         * Creating the URL variables and being valued by corresponding method parameters
         */
        Map<String, String> parameters = new HashMap<>();
//        parameters.put(USERID_PARAMETER_NAME, storeId);
        parameters.put(USERID_PARAMETER_NAME, "mr2");
//        parameters.put(VEHICLEID_PARAMETER_NAME, membershipIdentifier);
        parameters.put(VEHICLEID_PARAMETER_NAME, "VEH1");

        /**
         * Calling the rest webservice and returning response with body of type {@link AccMemberDetails}
         */
        ResponseEntity<String> response;
        MemberDetailsModel memberDetailsModel = null;
        AccMemberDetails accMemberDetails;
        try {
            response = restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);
            if (response == null || StringUtils.isBlank(response.getBody()) || EMPTY_RESPONSE.equals(response.getBody())) {
                throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier));
            } else {
                accMemberDetails = deserialize(response.getBody(), AccMemberDetails.class);
                String accErrorMessage = accMemberDetails.getUserMessage();
                if (!StringUtils.isBlank(accErrorMessage)) {
                    throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MESSAGE_FROM_API, "ACC", accErrorMessage));
                }
                memberDetailsModel = convert(accMemberDetails);
            }
        } catch (RestClientException e) {
            handleExceptions(e, storeId, membershipIdentifier);
        }
        return memberDetailsModel;
    }

    /**
     * This method is responsible for deserializing string REST response into an object of type {@link AccMemberDetails}
     */
    <T> T deserialize(final String response, final Class<T> responseClass) {
        try {
            return mapper.readValue(response, responseClass);
        } catch (IOException e) {
            throw new InternalServerException(resourceMessage.getMessage(MEMBER_ERROR_MAP_RESPONSE_OBJECT), e);
        }
    }

    /**
     * This method is responsible for converting an instance of type {@link AccMemberDetails} to an instance of type
     * {@link MemberDetailsModel}
     *
     * @param accMemberDetails an instance of type {@link AccMemberDetails}
     * @return an instance of type {@link MemberDetailsModel}
     */
    MemberDetailsModel convert(AccMemberDetails accMemberDetails) {
        MemberDetailsModel memberDetailsModel = new MemberDetailsModel();
        memberDetailsModel.setEventId(accMemberDetails.getEventId());
        memberDetailsModel.setMemberName(accMemberDetails.getMemberName());
        memberDetailsModel.setMembershipNumber(accMemberDetails.getMembershipNumber());
        memberDetailsModel.setMembershipLevel(accMemberDetails.getPricingLevel());
        return memberDetailsModel;
    }

    /**
     * This method is responsible for handling Exceptions may be thrown by ACC REST webservice
     *
     * @param e                    an instance of type {@link RestClientException}
     * @param storeId              an instance of type {@link String} and used in building exception messages
     * @param membershipIdentifier an instance of type {@link String} and used in building exception messages
     */
    private void handleExceptions(RestClientException e, String storeId, String membershipIdentifier) {
        if (e instanceof HttpStatusCodeException) {
            HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
            HttpStatus httpStatusCode = httpStatusCodeException.getStatusCode();
            if (404 == httpStatusCode.value()) {
                throw new ResourceNotFoundException(resourceMessage.getMessage(MEMBER_ERROR_NOT_FOUND, storeId, membershipIdentifier), e);
            } else if (500 == httpStatusCode.value()) {
                throw new InternalServerException(resourceMessage.getMessage(MEMBER_SERVER_ERROR, "ACC"), e);
            } else {
                throw new InternalServerException(resourceMessage.getMessage(MEMBER_HTTP_STATUS_CODE_ERROR, "HttpStatusCodeException", "ACC"), e);
            }
        } else {
            throw new InternalServerException(resourceMessage.getMessage(MEMBER_REST_CLIENT_ERROR, "RestClientException", "ACC"), e);
        }
    }

Problem

However I got UnhandledHttpStatusException after calling "restTemplate.exchange(dispatchURL, HttpMethod.GET, entity, String.class, parameters);" in the code snippet. the exception stack trace is as follows:

Caused by: org.springframework.web.client.UnknownHttpStatusCodeException: Unknown status code [443] null
    at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:60)
    at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:629)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:565)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:484)
    at com.blss.retailServices.memberServices.controllers.impl.acc.AccMemberDetailsApiControllerImpl.getMemberDetails(AccMemberDetailsApiControllerImpl.java:110)

Now I would be grateful if anyone could suggest me a solution.


Solution

  • I called this webservice with curl by using "-v" in order to get more info in response. As a result, I got the same exception (443) from their side. So, It sounds like they should have a better exception handler to return meaningful exception messages.