Passing Spring pageable in get request - spring

If I send a request from Spring application:
public ResponseEntity<RestResponsePage<Result>> readDocs(
Pageable pageable
) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Authorization", getToken());
String requestUri =
baseAppUrl + "/api/k" + "?page={page}&pageSize={pageSize}&sort={sort}&pageable={pageable}";
Map<String, Object> urlParameters = new HashMap<>();
urlParameters.put("page", Integer.toString(pageable.getPageNumber()));
urlParameters.put("pageSize", Long.toString(pageable.getPageSize()));
urlParameters.put("sort", pageable.getSort());
urlParameters.put("pageable", pageable);
HttpEntity<Void> requestEntity = new HttpEntity<>(requestHeaders);
ResponseEntity<RestResponsePage<Result>> response = restTemplate.exchange( RestResponsePage
requestUri,
HttpMethod.GET,
requestEntity,
new ParameterizedTypeReference<RestResponsePage<Result>>() {},
urlParameters
);
return response;
}
to another Spring application:
#GetMapping("/")
#PageableAsQueryParam
public ResponseEntity<Page<Result>> getAll(
#RequestHeader("Authorization") String token,
#RequestParam("page") Integer page,
#RequestParam("pageSize") Integer pageSize,
#RequestParam("sort") String sort,
#RequestParam("pageable") Pageable pageable
) {
...
}
I have got an error saying:
Resolved [org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable': no matching editors or conversion strategy found]
I know i can pass it seperately by fields like in example above:
page, pageSize etc.
But i want also to send Sort that's is inside Pageable object - that's also not correctly deserialized as a Type Sort.
How can I make it so Pageable is correctly deserialized ?
EDIT:
regarding answer, I added function like:
UriComponentsBuilder withPageable(UriComponentsBuilder builder,
Pageable pageable) {
builder.queryParam("page", pageable.getPageNumber()).queryParam("size",
pageable.getPageSize());
if (pageable.getSort() != null) {
StringBuilder sb = new StringBuilder();
pageable.getSort().forEach(order -> {
sb.append(order.getProperty()).append(",").append(order.getDirection());
});
builder.queryParam("sort", sb.toString());
}
return builder;
}
to make sort properly deserialize.

Do not need to use #RequestParam("pageable").
Pageable Abstract interface for pagination information.
pageSize, pageNumber, sort already provided on the Pageable
Sample Controller
#Controller
public class Controller {
#GetMapping("/...")
public List<...> findAll(Pageable pageable) {
log.debug("pageable: {}", pageable);
// ...
}
}
MockRequetBuilders
RequestBuilder request = MockMvcRequestBuilders.get("/url")
.param("page", "1")
.param("size", "5")
.param("sort", "name,DESC"); // column, ASC|DESC
ResultActions actions = mockMvc.perform(request);
actions.andExpect(...);
RestTemplate
URI uri = UriComponentsBuilder.fromHttpUrl("/url")
.queryParam("page", pageable.getPageNumber())
.queryParam("size", pageable.getPageSize())
.queryParam("sort", pageable.getSort())
.build()
.toUri();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<...> response = restTemplate.exchange(uri, HttpMethod.GET, entity, ...);
https://reflectoring.io/spring-boot-paging/
https://cursos.alura.com.br/forum/topico-no-primary-or-single-unique-constructor-found-for-interface-org-springframework-data-domain-pageable-195442

Related

how to return only HTTP Status code, if we hit one pre-defined endpoint

When I hit
#FeignClient(name = "abc_abc", url = "${abc.host}")
public interface validateClient {
#PostMapping(path = "/api/abc/validate",
consumes = "application/json",
produces = "application/json")
**public <?> validateResponse**(#RequestHeader HttpHeaders htppHeaders, #RequestParam Map<String, Object> params,
#RequestBody String request);
}
in this example API: /api/abc/validate
i just want to return only HTTP status code
what is the return type of validateResponse method ? please some one plz suggest
Try use ResponseEntity without any "body", here an example.
#PostMapping(path = "/api/abc/validate",
consumes = "application/json",
produces = "application/json")
public ResponseEntity validateResponse(#RequestHeader HttpHeaders htppHeaders, #RequestParam Map<String, Object> params,
#RequestBody String request) {
return ResponseEntity.status(HttpStatus.FOUND).build();
}
You can choose from standard HttpStatus enum, or simply insert an integer for your custom needs

Spring boot: Sending a JSON to a post request that uses a model as a param

Lets say I have a predefined post mapping as such:
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}
and the valDetail object as follows:
#Data
#Component
#Entity
#Table(name = "val_portal")
public class valDetail {
#Id
#Column(name = "valcode")
private String valCode;
#Column(name = "valname")
private String valName;
}
How would I go about actually sending JSON values from a separate service to this /add endpoint so that they are properly received as a valDetail object?
Currently I tried this implementation but I keep getting a 415 response code.
JSONObject valDetail = new JSONObject();
valDetail.put("valCode",request.getAppCode().toLowerCase());
valDetail.put("valName", request.getProjectName());
String accessToken = this.jwtUtility.retrieveToken().get("access_token").toString();
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setBearerAuth(accessToken);
authHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(valDetail.toString(), authHeaders);
ResponseEntity<String> loginResponse = restTemplate.exchange(uri,
HttpMethod.POST,
entity,
String.class);
If you want to pass data as json you don't want to take Model try to use #ResponseBody annotation to transfer data through json.
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<String> addVal(#RequestBody final valDetail newVal) {
//Do Stuff
}

RestTemplate.exchange doesn't work properly. Missing params thrown

I've got 2 aplication one calling another. In the first one I have
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
parameters.add("stationFrom", stationfrom);
parameters.add("stationTo", stationto);
parameters.add("operator", 5);
parameters.add("dateTimeFrom", sdfnative.format(sdfeskm.parse(departuredate)));
parameters.add("dateTimeTo", sdfnative.format(sdfeskm.parse(departuredate).getTime() + 60*60*1000));
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(parameters, headers);
jsonTrain = restTemplate.exchange(url, HttpMethod.GET, request, String.class).toString();
the url is defined as global http://ip:8090/connection/search
When I'm looking at the request I can see that every parameter has it's proper value, but in the restTemplate.exchange line I got error "Parameter stationFrom is missing"
My endpoint on provided IP looks like :
#GetMapping(value = "/connection/search")
public ResponseEntity<String> getConnection(#RequestParam(value = "stationFrom") int stationFrom,
#RequestParam(value = "stationTo") int stationTo,
#RequestParam(value = "operator") int operator,
#RequestParam(value = "dateTimeFrom") String dateTimeFrom,
#RequestParam(value = "dateTimeTo") String dateTimeTo) throws JSONException
I don't know why it throws me this error if stationFrom has for example value 40 and I can see it in debug/logs
Of course calling provided endpoint from postman, with the same data gives me expected result :)
You are passing the query parameters (RequestParams) as headers.
Check the following example how to pass RequestParams:
public void findUserById()
{
String username = "chathuranga";
String password = "123";
Integer userId = 1;
String url = "http://localhost:" + port + "/users/" + userId;
//setting up the HTTP Basic Authentication header value
String authorizationHeader = "Basic " + DatatypeConverter.printBase64Binary((username + ":" + password).getBytes());
HttpHeaders requestHeaders = new HttpHeaders();
//set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
//request entity is created with request headers
HttpEntity<AddUserRequest> requestEntity = new HttpEntity<>(requestHeaders);
//adding the query params to the URL
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("name", "chathuranga")
.queryParam("email", "chathuranga.t#gmail.com");
ResponseEntity<FindUserResponse> responseEntity = restTemplate.exchange(
uriBuilder.toUriString(),
HttpMethod.GET,
requestEntity,
FindUserResponse.class
);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
System.out.println("response received");
System.out.println(responseEntity.getBody());
} else {
System.out.println("error occurred");
System.out.println(responseEntity.getStatusCode());
}
}

Get specific response value from the API in SpringBoot

I am calling one post call and getting the response like below :
Now I want to get the value of the access token and do some logic. How to get the value from the response? Can anyone please help.
Service code of the API.
public String getToken(User user) throws JsonMappingException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(clientId+clientPass);
String plainCreds = clientId+":"+clientPass;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.getEncoder().encode(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
HttpEntity<String> request=new HttpEntity<String>(headers);
String uri = url+ user.getUser_id()
+ "&password=" + user.getPassword();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST, request, String.class) ;
JsonNode newNode = mapper.readTree(result.getBody());
ObjectNode node = ((ObjectNode) newNode).put("Authentication", "Successful");
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
}
I was able to figure it out.
I used
node.get("access_token")
And it worked!
You can write DTO for response:
public class ResponseSample {
#JsonProperty("access_token")
String accessToken;
....
}
(or deserialize to Map)
and instead calling ResponseEntity<String> result = restTemplate.exchange(...) you can call
ResponseEntity<ResponseSample> result = restTemplate.exchange(..., ResponseSample.class)

Spring RestTemplate Handling Multiple Responses

I'm consuming a restful service, What I observed is based on the request I see multiple responses for the same end point.
For Ex : I request a GET call with the some parameters for a PDF document.
if the response is good and the content type is application/pdf its giving a pdf document.
if the document is not available, the content type is application/xml and the response is giving the error code, error description.
Any input is much appreciated !
Thanks,
Sudheer.
You can use the ResponseEntity class of Spring, you can set the class to return the object what you want. You can change the content type, and everything you want.
here there is an example of file
#RequestMapping(value = URIConstansts.GET_FILE, produces = { "application/json" }, method = RequestMethod.GET)
public #ResponseBody ResponseEntity getFile(#RequestParam(value="fileName", required=false) String fileName,HttpServletRequest request) throws IOException{
ResponseEntity respEntity = null;
byte[] reportBytes = null;
File result=new File("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
if(result.exists()){
InputStream inputStream = new FileInputStream("/home/arpit/Documents/PCAP/dummyPath/"+fileName);
String type=result.toURL().openConnection().guessContentTypeFromName(fileName);
byte[]out=org.apache.commons.io.IOUtils.toByteArray(inputStream);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("content-disposition", "attachment; filename=" + fileName);
responseHeaders.add("Content-Type",type);
respEntity = new ResponseEntity(out, responseHeaders,HttpStatus.OK);
}else{
respEntity = new ResponseEntity ("File Not Found", HttpStatus.OK);
}
return respEntity;
}
Here there is an example of Json
#ResponseBody ResponseEntity<? extends AbstractResponse> createUser(#RequestBody String requestBody) {
if(!valid(requestBody) {
ErrorResponse errResponse = new ErrorResponse();
//populate with error information
return new ResponseEntity<ErrorResponse> (errResponse, HTTPStatus.BAD_REQUEST);
}
createUser();
CreateUserSuccessResponse successResponse = new CreateUserSuccessResponse();
// populate with more info
return new ResponseEntity<CreateUserSuccessResponse> (successResponse, HTTPSatus.OK);
}

Resources