Spring restTemplate issue in getting response - java

My rest server is generating response when I called it with rest client software. When I call it with resttemplate code mentioned above, then server generates response(print logs) but resttemplate does nothing(no next line executes after call) and prints internal error.
This is the method in my server
#ResponseBody
public ResponseEntity<Map<String, Object>> name(){......
...
return new ResponseEntity<Map<String, Object>>(messagebody, HttpStatus.OK);
}
This is the way I am calling it through restTemplate
ResponseEntity<Map> response1 = restTemplate.getForEntity(finalUrl.toString(), Map.class);

Try to use ParameterizedTypeReference instead of wildcarded Map.
It should looks like this.
ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() {};
ResponseEntity<Map<String, Object>> response = restTemplate.exchange(finalUrl.toString(), HttpMethod.GET, null, typeRef);

this is a example that works for me
#RequestMapping(value = "/getParametros/{instancia}", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> getParametros(#PathVariable String instancia)
{
LOG.debug("REST. Obteniendo parametros del servidor " + instancia);
Map<String, String> mapa = parametrosService.getProperties(instancia);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=UTF-8");
headers.add("X-Fsl-Location", "/");
headers.add("X-Fsl-Response-Code", "302");
ObjectMapper mapper = new ObjectMapper();
String s = "";
try
{
s = mapper.writeValueAsString(mapa);
} catch (JsonProcessingException e)
{
LOG.error("NO SE PUEDE MAPEAR A JSON");
}
if (mapa == null)
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<String>(s, headers, HttpStatus.OK);
}

you can Catch the HttpStatusCodeException from which you can get response in String .
below code works for me.
restTemplate.postForObject( url, jsonRequest, ResponseData.class );
catch( HttpStatusCodeException codeException )
{
String payload = codeException.getResponseBodyAsString();
System.out.println( payload );
}

Related

How to sent Http POST request with application/x-www-form-urlencoded

I'm trying to generate a token from an external website, the post request must be application/x-www-form-urlencoded but I'm getting errors. I assume that I'm not making the right call for the content type application/x-www-form-urlencoded but I can't figuer out how!!
PS: I'm using springboot with java 8
here is the code:
public String getNewAccesToken() {
//Initilazing variabels
try {
JsonObject properties = new JsonObject();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Cookie", cookie);
properties.addProperty("client_id", clientId);
properties.addProperty("client_secret", clientSecret);
properties.addProperty("grant_type", grantType);
HttpEntity<String> requestEntity = new HttpEntity<>(properties.toString(), headers);
log.debug(requestEntity);
ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.POST, requestEntity,
String.class);
log.debug("---------------------------------");
log.debug(response);
if (Util.isJSONValid(response.getBody())) {
JsonParser parser = new JsonParser();
JsonObject jsonString = (JsonObject) parser.parse(response.getBody());
return jsonString.get("accessToken").getAsString();
} else {
error.setCode(ConstantGateway.JSON_ERROR_CODE);
error.setMessage(ConstantGateway.JSON_ERROR_STATUS);
return error.toString();
}
} catch (HttpStatusCodeException e) {
error.setCode(String.valueOf(e.getStatusCode().value()));
error.setMessage(e.getResponseBodyAsString());
return error.toString();
} catch (Exception e) {
// TODO: handle exception
error.setCode(ConstantGateway.IL_INTERNAL_ERROR_CODE);
error.setMessage(e.getMessage());
return error.toString();
}
}
and here is what I get when calling this function:
org.zwz.vas.internal.api.model.ErrorModel#16dd359c
However when I make the call from Postman I get the right response which is :
{
"access_token": "RdWt3DNIfxmihnubGX0Fgfcb0KNHLZV79OfN9Y6Ky6Z3fxAfF_Pm7uP0jnFrG1fHplyBMZ74BIKleQ8jmswdGy4e87NV-uZsMzgS1nQAONc2nBxgU1_jkMBhL4vvIniJNd99oYNzGeanCYYki0yorrrlLrOGTncusv1BgFFHU_CBGuUtGmZYLfJAJW4XcZLhXMC9xpT2aWAvgRXZW69pOhfU1Fgs7aVwou85UVI2b4j1GfX0pCtJtluiTgXsuWqdck7_at1dqfopHpjWAywYrweStMXGm8T59nyQi_oXWmo",
"token_type": "bearer",
"expires_in": 1199
}
THANK YOU IN ADVANCE
I find the mistake I did, I was sending a wrong request format which is not compatibale with application/x-www-form-urlencoded type. The right code is below:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Cookie", cookie);
MultiValueMap<String, String> properties= new LinkedMultiValueMap<String, String>();
properties.add("client_id", clientId);
properties.add("client_secret", clientSecret);
properties.add("grant_type", grantType);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(properties, headers);
ResponseEntity<String> response = restTemplate.postForEntity( requestUrl, request , String.class );

How can we make asynchronous REST api call in Java?

I am using Spring RestTemplate and want to make a call to another service that doesn't return any response body. So, I don't want to wait for the response. So, it's just fire and forget, and continue with the remaining code. I am thinking of creating a new Thread to do this but really not sure what's the correct approach.
If you use Java 11, java support asynchronous HTTP Client. Asynchronous client using CompletableFuture in the back. You can see javadoc.
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://openjdk.java.net/"))
.timeout(Duration.ofMinutes(1))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(response -> { System.out.println(response.statusCode());
return response; } )
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
The correct approach is to execute the async with a callback (using DeferredResult, like this (assuming we have a class someClass that we want to retrieve from the API:
#GetMapping(path = "/testingAsync")
public DeferredResult<String> value() throws ExecutionException, InterruptedException, TimeoutException {
AsyncRestTemplate restTemplate = new AsyncRestTemplate();
String baseUrl = "http://someUrl/blabla";
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
String value = "";
HttpEntity entity = new HttpEntity("parameters", requestHeaders);
final DeferredResult<String> result = new DeferredResult<>();
ListenableFuture<ResponseEntity<someClass>> futureEntity = restTemplate.getForEntity(baseUrl, someClass.class);
futureEntity.addCallback(new ListenableFutureCallback<ResponseEntity<someClass>>() {
#Override
public void onSuccess(ResponseEntity<someClass> result) {
System.out.println(result.getBody().getName());
result.setResult(result.getBody().getName());
}
#Override
public void onFailure(Throwable ex) {
result.setErrorResult(ex.getMessage());
}
});
return result;
}
There are many ways you can use to fire the request using the AsyncRestTemplate
The simplest way is just like restTemplate and call exchange method:
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
JSONObject json = new JSONObject();
json.put("firstName","testUser");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<String>(json.toString(), headers);
Class<String> responseType = String.class;
ListenableFuture<ResponseEntity<String>> future = asyncRestTemplate.exchange("https://xxxxx.com/", HttpMethod.POST, requestEntity,responseType );
// If you want for the result then you can use
try {
//waits for the result
ResponseEntity<String> entity = future.get();
//prints body source code for the given URL
log.info(entity.getBody());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
If we want to play with the failure (fallback scenario) or success in that case we can use the below code :
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
JSONObject json = new JSONObject();
json.put("firstName","testUser");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<String>(json.toString(), headers);
//final DeferredResult<String> result = new DeferredResult<>();
ListenableFuture<ResponseEntity<String>> future =
asyncRestTemplate.postForEntity("https://xxxx.com", requestEntity, String.class);
future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
#Override
public void onFailure(Throwable ex) {
// insert into the table or log or some other decision
log.info(ex.getMessage());
}
#Override
public void onSuccess(ResponseEntity<String> result) {
log.info(result.getBody());
log.info("Sucess");
}
});

How do I mock RestTemplate exchange using junit 5 (Jupiter)

I tried with below code but in response body I got empty records.
Please help me on below code.
Java Code:
public Customer getCustomers(String customerId, String authorization) {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.set("Authorization", authorization);
HttpEntity<Customer> request = new HttpEntity<>(headers);
Map<String, Object> params = new HashMap<>();
params.put("CustomerId", customerId);
String url = "https://localhost:8080/api/customer/{CustomerId}/get";
ResponseEntity<Customer> response = restTemplate.exchange(
url,
HttpMethod.GET,
request,
Customer.class,
params
);
Customer customer = null;
if (response != null && response.getBody() != null) {
customer = response.getBody();
}
return customer;
}
Test Code:
#Test
public void testGetCustomersSuccess() {
Customer customer = new Customer();
customer.setCountryCode("countryCode");
customer.setCreatedFrom("createdFrom");
customer.setCustomerlandline("224153");
customer.setCustomermobile("1522252");
customer.setEmail("email");
customer.setFirstname("firstName");
customer.setFiscalCode("fiscalCode");
customer.setFirstname("lastName");
customer.setId("5");
MultiValueMap<String, String> headers=new LinkedMultiValueMap<>();
headers.set(Authorization,"12152");
ResponseEntity<Customer> response=new ResponseEntity<Customer>(HttpStatus.OK);
when(restTemplate.exchange(Mockito.any(String.class),
Mockito.<HttpMethod> any(),
Mockito.<HttpEntity<Customer>> any(),
Mockito.<Class<Customer>> any(),
Mockito.<String, Object> anyMap()))
.thenReturn(response);
assertEquals(response.getBody(),serviceClientImpl.getCustomers("5", "12152"));
}
You need to set the value of customer in your response.
The values you are setting in customer object is not being used anywhere.
Try this:
ResponseEntity<Customer> response=new ResponseEntity<Customer>(customer,HttpStatus.OK);

Mock to POST HTTP request get null pointer exception

I have this method
public HTTPResult post(String url, String requestBody) throws Exception {
return HTTPPostPut(url, requestBody, HttpMethod.POST);
}
public HTTPResult HTTPPostPut(String url, String requestBody,HttpMethod httpMethod) throws Exception {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("content-type","application/json");
HttpEntity requestEntity = new HttpEntity(requestBody,headers);
try {
ResponseEntity<String> response = this.restTemplate.exchange(url, httpMethod, requestEntity, String.class);
return new HTTPResult((String) response.getBody(), response.getStatusCode().value());
} catch (ResourceAccessException var8) {
String responseBody = var8.getCause().getMessage();
JSONObject obj = new JSONObject(responseBody);
return new HTTPResult(obj.getString("responseBody"), Integer.parseInt(obj.getString("statusCode")));
}
}
Which I created for it mock and getting null pointer exception:
public void testPost() throws Exception{
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("content-type","application/json");
HttpEntity requestEntity = new HttpEntity("{blbl}",headers);
ResponseEntity<String> response = new ResponseEntity("{blbl}", HttpStatus.OK);
RestTemplate mockRestTemplate = mock(RestTemplate.class);
when(mockRestTemplate.exchange(baseUrl, HttpMethod.POST, requestEntity, String.class)).thenReturn(response);
RestAPI api = new RestAPI(mockRestTemplate);
HTTPResult res = null;
try {
res = api.post(baseUrl,"{blbl}");
} catch (IOException e) {
e.printStackTrace();
}
assertEquals(res.getResponseBody(), "{blbl}");
assertEquals(res.getStatusCode(), HttpStatus.OK.value());
}
I am getting null pointer exception when calling:
res = api.post(baseUrl,"{blbl}");
This is because the response is null.
Use an argument matcher when arranging the mock as the instance being passed to the mocked dependency is different to what is passed when the test is exercised.
This will cause the mock to return null response as expected instances do not match
Refactor the test
public void testPost() throws Exception {
//Arrange
String expected = "{blbl}";
ResponseEntity<String> response = new ResponseEntity(expected, HttpStatus.OK);
RestTemplate mockRestTemplate = mock(RestTemplate.class);
when(mockRestTemplate.exchange(eq(baseUrl), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)))
.thenReturn(response);
RestAPI api = new RestAPI(mockRestTemplate);
//Act
HTTPResult res = api.post(baseUrl, expected);
//Assert
assertEquals(res.getResponseBody(), expected);
assertEquals(res.getStatusCode(), HttpStatus.OK.value());
}
Note the use of the any(HttpEntity.class) matcher which will allow the passed HttpEntity to be matched when invoked.
Since the use of argument matches is none or all, the eq() matcher is used for the remaining constant arguments.

How to use Spring RestTemplate instead of Apache Httpclient?

I want to use Spring RestTemplate instead of Apache HttpClient for working with a remote API
With HttpClient
// build request JSON
JSONObject json = new JSONObject();
json.put("username", username);
json.put("serial", serial);
json.put("keyId", keyId);
json.put("otp", otp);
String json_req = json.toString();
// make HTTP request and get response
HttpPost request = new HttpPost(AuthServer);
request.setHeader("Content-Type", "application/json");
request.setEntity(new StringEntity(json_req));
response = client.execute(request);
With RestTemplate
Map<String, String> paramMap = new HashMap<String,String>();
paramMap.put("username", userName);
paramMap.put("serial", serial);
paramMap.put("keyId", keyId);
paramMap.put("otp", otp);
String mapAsJson = new ObjectMapper().writeValueAsString(paramMap);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<String>(mapAsJson,requestHeaders);
try {
ResponseEntity<String> response = restTemplate.exchange(AuthServer, HttpMethod.POST, request, String.class);
return response.getHeaders();
} catch (HttpClientErrorException e) {
return null;
}
}
The code with HttpClient works but that with RestTemplate does not. I don't know how to use StringEntity in RestTemplate.
Spring version is 3.0.0, and JVM is 1.6.
RestTemplate is better suited to working with objects. As an example:
AuthenticationRequest.java
class AuthenticationRequest {
private String username;
private String serial;
private String key;
private String otp;
}
AuthenticationResponse.java
class AuthenticationResponse {
private boolean success;
}
AuthenticationCall.java
class AuthenticationCall {
public AuthenticationResponse execute(AuthenticationRequest payload) {
HttpEntity<AuthenticationRequest> request = new HttpEntity<AuthenticationRequest>(payload, new HttpHeaders());
return restTemplate.exchange("http://www.domain.com/api/endpoint"
, HttpMethod.POST
, request
, AuthenticationResponse.class).getBody();
}
}
These classes can be used as follows:
if(new AuthenticationCall().execute(authenticationRequest).isSuccess()) {
// Authentication succeeded.
}
else {
// Authentication failed.
}
All of this requires there to be a JSON library such as Jackson or GSON on the classpath.

Categories

Resources