Java Supplier<> get origins information - java

I Use the Supplier in my code to call restTemplate and make the custom Message when have exception..
But, im my message, i need get information by my requestCall, But when i cast the request the java thow error
...
My code:
public void execute() {
HttpHeaders headers = buildDefaultHeaders();
UriBuilder uri = UriBuilder.fromUri(wdd3dGatewayEndpoint + API_URL);
HttpEntity request = new HttpEntity(headers);
this.executeRequest(() -> restTemplate.exchange(uri.build(), HttpMethod.DELETE, request, Void.class));
}
My Supplier
protected ResponseEntity executeRequest(Supplier<ResponseEntity> request) {
try {
ResponseEntity response = request.get();
updateSessionToken(response);
return response;
} catch (HttpClientErrorException | HttpServerErrorException e) {
String msg = "WDD3D-Error in service communication<br>" + e.getResponseBodyAsString();
throw new MaestroException(msg);
}
}
Now, i try cast to get URL...
protected ResponseEntity executeRequest(Supplier<ResponseEntity> request) {
try {
ResponseEntity response = request.get();
updateSessionToken(response);
return response;
} catch (HttpClientErrorException | HttpServerErrorException e) {
//THROW EXEPTION HERE... PLEASE HELP...
RequestEntity requestEntity = (RequestEntity) request;
String url = requestEntity.getUrl().toString();
String msg = "WDD3D-Error in service communication<br>" + e.getResponseBodyAsString();
throw new MaestroException(msg);
}
}]

You should use the get() method of the Supplier, see more in the docs.

RequestEntity requestEntity = (RequestEntity) request;
You are trying to cast a Supplier<ResponseEntity> to a RequestEntity.
These are two very different classes and such a cast will never work.
Maybe you want to call request.get() and get the URL from the ResponseEntity that you have.
Tell me if it works for you in the comments or we need to debug further ?

The only thing you are trying to get from the RequestEntity is the URL, which you can't get from the Supplier<ResponseEntity> since it is not a RequestEntity, so why not just pass the URL as another parameter to executeRequest? Then it would have the additional information it needs to log the error.

Related

Spring HttpClientErrorException and RestClientException getting request URL

I have more then 1 http call in try-catch block, exmaple:
try {
HttpHeaders httpHeaders = new HttpHeaders();
ResponseEntity<String> sendGet = http.sendGet(someUrl1, httpHeaders);
ResponseEntity<String> sendPost = http.sendPost(someUrl2, httpHeaders);
}catch(HttpClientErrorException e) {
//print call url here someUrl1/someUrl2
printException(e);
}
catch (Exception e) {
printException(e);
//general e
}
//Print exception
public void printException(Exception e){
//log URL here
}
I want to print the failed URL when I catch the exception but I did not find HttpClientErrorException or RestClientException property that I can use.
EDIT for general case:
I don't think you should use HttpClientErrorException for getting url, you know the URL before calling each request, so my suggestion:
Create a generic send method which receive post method, URL and headers parameters
Call your method for each request and it will also handle exceptions based on current URL
For simple case describe in question:
You can split to 2 try and catch blocks for each request
Or add a boolean ( or currentUrl String variable)
boolean isFirstRequestFinished = false;
Set it to true after first request and check in catch block
if (isFirstRequestFinished) {

Response status code showing 200 for gateway error (504)

I have a REST endpoint which call another API which take a while to process and returning 504 error when I verify through Rest client (Insomnia). But in my service I see this transaction as success 200 not 504.
Below is how my code snippet:
public ResponseEntity<Customer> processResponse(Customer customer, String restUri) {
ResponseEntity<Customer> response;
String customerJson = null;
try {
RestTemplate restTemplate = restTemplateBuilder.basicAuthorization(userName, password).build();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Customer> entity = new HttpEntity<>(customer, headers);
CustomerJson = jacksonUtil.toJSON(customer);
response = restTemplate.exchange(restUri, HttpMethod.PUT, entity, Customer.class);
if (response.getStatusCode().is2xxSuccessful()) {
logger.info("Return success from the server");
} else {
logger.error("Error while getting the response from the server");
}
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
return response;
}
What am I missing here? Why its not executing the else block?
Thanks in advance.
Your method seems to be returning null response in case of error. Can you check if you have done any handling in caller and passing 200 from controller layer itself.

restTemplate postForEntity sometimes leads into 400 Error

In my Android app I try to make a POST via restTemplate.postForEntity() but the first time I try to post the data I get a 400 error. After my timetrigger sync-method try to post the data again it works and I get 200. I don't think it's a backend problem, because I did a couple requests via Swagger and Postman on the same interface and all of them worked without a problem.
This is the error I get:
POST request for "<url>" resulted in 400 (); invoking error handler
org.springframework.web.client.HttpClientErrorException: 400
This is what I see at the postForEntity() when I'm debugging:
'java.lang.NullPointerException' Cannot evaluate org.springframework.http.ResponseEntity.toString()
This is the code:
public ResponseEntity<ArrayList> postServiceData(List<BasicService> attributes) {
HttpStatus status = null;
ResponseEntity<ArrayList> chargerServiceResponse = new ResponseEntity<ArrayList>(status);
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<?> entity = RestServiceUtils.getHttpEntity(attributes, context);
chargerServiceResponse = restTemplate.postForEntity(url, entity, ArrayList.class);
SynchronisationStorage synchronisationStorage = new SynchronisationStorage(context);
synchronisationStorage.updateLastSynchronisationDate();
loggingStorageDbHelper.logSuccess(R.string.logging_save_send_charger_service_to_backend, 1000);
} catch (HttpClientErrorException e) {
/* do stuff*/
}
}
To set the body and token:
#NonNull
public static HttpEntity<?> getHttpEntity(List attributes, Context context) {
HttpHeaders headers = new HttpHeaders();
try {
headers.set(ServiceAppConstants.HEADER_ACCEPT, ServiceAppConstants.MEDIATYPE_JSON);
UserStorage userStorage = new UserStorage(context);
String token = userStorage.getJsonWebToken();
headers.set(ServiceAppConstants.HEADER_SECURITY_TOKEN, token);
}catch (Exception ex){
Log.e(RestServiceUtils.class.getName(), "Exception ocurred while trying to set token to header", ex);
}
return new HttpEntity<Object>(attributes, headers);
}

Response Entity is null despite Error-404 JSON returned by a server

I am using Spring REST to handle my requests.
Here is my code sample:
RestTemplate restTemplate = new RestTemplate();
HttpEntity entity = new HttpEntity(headers);
ResponseEntity<String> responseEntity = null;
try {
responseEntity = restTemplate.exchange(apiAddress + "action?uniqueId=" + id, HttpMethod.GET, entity, String.class);
}catch (RestClientException ex) {
System.out.println(responseEntity.toString());
String errorMessage = ex.getMessage();
}
Everything is OK when I have got 200 status and JSON with returned values.
The problem is with, for example, 404 JSONs.
During the debugging I have figured out that when 404 occurs my responseEntity is still null so I am unable to get the error code. Moreover I am unable to get JSON reply from the server which I know that it being send.
I tried HTTP Requester which works fine with 200 responses - giving me requested data and with 404 responses - giving me a JSON with error description.
Best Regards,
Karol
I have managed to figure out what is going on.
I Hope that it might help someone else:
I have implemented ResponseErrorHandler :
public class VariousErrorsResponseHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
if(clientHttpResponse.getStatusCode() == HttpStatus.NOT_FOUND || clientHttpResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) return false;
else return true;
}
#Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
System.err.println(clientHttpResponse.getStatusCode() + "\n" + clientHttpResponse.getStatusText());
}
}
Then set it as restTemplate's error handler:
restTemplate.setErrorHandler(new VariousErrorsResponseHandler());
And done :)

restTemplate delete with body

I am trying to do DELETE with request body but I keep getting 400 (bad request) error. When I do it in the swagger/postman, it is successfully deleting the record. But from the Java code I can't do that
The external API is designed in a way that it needs body along with URL. It can't be changed. please let me know how can I delete that entry with request body
public Person delete(Person person, String url, Map<String, String> uriVariables) throws JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
CustomObjectMapper mapper = new CustomObjectMapper();
HttpEntity<Person> requestEntity = new HttpEntity<Person>(person);
try {
ResponseEntity<Person> responseEntity = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Person.class, uriVariables);
return responseEntity.getBody();
} catch (RestClientException e) {
System.out.println(mapper.writeValueAsString(person));
throw e;
}
}
when it goes to exception, I will get the JSON request in JSON format and the same works fine in Swagger/postman
I did some googling and found that restTemplate have problem deleting when there is request body. this article wasn't helpful https://jira.spring.io/browse/SPR-12361 is there any way to get it work
Another way to fix this is to use restTemplate.exchange, here's an example:
try {
String jsonPayload = GSON.toJson(request);
HttpEntity<String> entity = new HttpEntity<String>(jsonPayload.toString(),headers());
ResponseEntity resp = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class);
} catch (HttpClientErrorException e) {
/* Handle error */
}
The nice thing about this solution is that you can use it with all HttpMethod types.
Issue exists for Spring version 4.0.x or earlier.
In later version it has been fixed.
This might be a late answer, but in one of my project I solved this issue via a custom ClientHttpRequestFactory to RestTemplate
If no factory is provided to RestTemplate, it uses default implementation SimpleClientHttpRequestFactory
In SimpleClientHttpRequestFactory class, DELETE method is not allowed with request body.
if ("PUT".equals(httpMethod) || "POST".equals(httpMethod) ||
"PATCH".equals(httpMethod)) {
connection.setDoOutput(true);
}
else {
connection.setDoOutput(false);
}
Just write your own implementation as
import java.io.IOException;
import java.net.HttpURLConnection;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
public class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
#Override
protected void prepareConnection(HttpURLConnection connection,
String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
if("DELETE".equals(httpMethod)) {
connection.setDoOutput(true);
}
}
}
After that create your RestTemplate object as
RestTemplate template = new RestTemplate(
new CustomClientHttpRequestFactory());
Fix in later versions of (4.1.x or above) SimpleClientHttpRequestFactory class
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
"PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
connection.setDoOutput(true);
}
else {
connection.setDoOutput(false);
}

Categories