Test method issue - spring-mvc

I tried this code:
//CONTROLLER
#GetMapping(path = "/validateToken/{id}")
public ResponseEntity<Boolean> validateToken(#PathVariable String id) {
try {
boolean bool=webSSOService.validateToken(id);
return new ResponseEntity<Boolean>(bool, HttpStatus.OK);
} catch (Exception e) {
LOGGER.error(Message.ERROR_OCCURRED+Thread.currentThread().getStackTrace()[1].getMethodName()+": "+ e.getMessage());
if (LOGGER.isDebugEnabled()) {
e.printStackTrace();
}
return new ResponseEntity<Boolean>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
//SERVICE
#Override
public boolean validateToken(String id) throws JsonProcessingException {
Map<String,Object> parameters=new HashMap<>();
parameters.put("id",id);
String uri="/SSOServiceToken/validateToken/{id}";
HttpMethod httpMethod=HttpMethod.GET;
boolean bool=executeFilteredRequest(parameters,uri,Boolean.class,httpMethod);
return bool;
}
private <T> T executeFilteredRequest(Map<String,Object> parameters, String uri, Class<T> type, HttpMethod httpMethod) throws JsonProcessingException {
RestTemplate restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
headers.setContentType(MediaType.APPLICATION_JSON);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8180" + uri);
String jsonBody="";
if (httpMethod == HttpMethod.POST){
ObjectMapper objectMapper=new ObjectMapper();
jsonBody=objectMapper.writeValueAsString(parameters);
}else{
parameters.forEach( (key, value) -> builder.queryParam(key,value));
}
HttpEntity<?> entity = new HttpEntity<>(jsonBody,headers);
ResponseEntity<T> response = restTemplate.exchange(builder.toUriString(),
httpMethod,
entity,
type);
return response.getBody();
}
Then I have to test validateToken:
#Test
public void validateTokenIsOk() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/validateToken/{id}","c8r1p15dv5lr0on")
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
}
The method validateToken takes an id Token, which its flag is false, in input, and then its output should become true.
Now, I always obtain a 200 status code and false as response, in every case, when I try to perform the test with Intellij. Furthermore, I obtain a message: "Token '%7Bid%7D' not found on database".
But if I try to test with Postman, result is true as expected.
What's wrong with my code? Why is the id"%7Bid%7D", instead of "c8r1p15dv5lr0on"? How is "%7Bid%7D" generated?
I hope I was clear in my question.
Thank you very much!

Problem solved. In my service:
#Override
public boolean validateToken(String id) throws JsonProcessingException {
Map<String,Object> parameters=new HashMap<>();
String uri="/SSOServiceToken/validateToken"+id;
.
.
.
That "%7Bid%7D" string was an encoded one of "{id}" in uri variable. So, in order to avoid that spurious string, I need to concatenate my uri with id variable.

Related

How to get response statusCode from filterRequest function Ballerina

I am new in Ballerina, I try to print a log that containe some request informations like path .. and statusCode which is a response information.
How can I do that safely ?
I want to make the both logs in same log
public function filterRequest(http:Caller caller, http:Request request, http:FilterContext context) returns boolean {
log:printInfo(remoteAdress + " " + request.method + " " + request.rawPath);
return true;
}
public function filterResponse(http:Response response, http:FilterContext context) returns boolean {
log:printInfo(response.statusCode.toString());
return true;
}
Currently only service name and resource name can be accessed from http:FilterContext by default. However, any request properties such as rawPath and method can be added to the http:FilterContext attributes map. This can be retrieved in the http:ResponseFilter
public type RequestFilter object {
*http:RequestFilter;
public function filterRequest(http:Caller caller, http:Request request,
http:FilterContext context) returns boolean {
map<any> attributesMap = context.attributes;
attributesMap["rawPath"] = request.rawPath;
attributesMap["method"] = request.method;
return true ;
}
};
public type ResponseFilter object {
*http:ResponseFilter;
public function filterResponse(http:Response response,
http:FilterContext context) returns boolean {
log:printInfo(context.getServiceName());
log:printInfo(context.getResourceName());
log:printInfo(context.attributes["rawPath"].toString());
log:printInfo(context.attributes["method"].toString());
return true ;
}
};

How to read HTTP 500 using a Spring RestTemplate client

A simple Spring Boot REST Controller
#PostMapping(path = "check-and-submit", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyOutput> checkAndSave(#RequestBody #Valid MyInput input, Errors errors){
ResponseEntity<MyOutput> result = null;
if (errors.hasErrors()) {
result = new ResponseEntity<>(MyOutput.buildErrorResponse(errors), HttpStatus.INTERNAL_SERVER_ERROR);
} else {
myDao.save(input.buildEntity());
result = new ResponseEntity<>(MyOutput.buildSuccessResponse(), HttpStatus.OK);
}
return result;
}
And the test class for it
public static void main(String[] args) {
MyInput dto = new MyInput();
// set properties
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<MyInput> request = new HttpEntity<MyInput>(dto, headers);
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
System.out.println(result);
} catch(Exception e) {
e.printStackTrace();
}
}
For success scenario this works fine. But, for exception scenrio, i.e. HTTP 500 this fails
org.springframework.web.client.HttpServerErrorException: 500 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:97)
As suggested in one of the posts, I created a error-handler that can successfully read the response
public class TestHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
Scanner scanner = new Scanner(response.getBody());
String data = "";
while (scanner.hasNext())
data += scanner.next();
System.out.println(data);
scanner.close();
}
}
But how can I let RestTemplate read and deserialize the response JSON even in case of HTTP 500.
Before any other human-question-flagging-bot marks this as duplicate, here's a humble explanation on how this is different from the others.
All other questions address how to handle HTTP 500, at max read the response-body. This questions is directed at if it is possible to deserialize the response as JSON as well. Such functionality is well established in frameworks such as JBoss RESTEasy. Checking how same can be achieved in Spring.
This should work.
try {
ResponseEntity<MyOutput> result = restTemplate.postForEntity(URL, request, MyOutput.class);
} catch(HttpServerErrorException errorException) {
String responseBody = errorException.getResponseBodyAsString();
// You can use this string to create MyOutput pojo using ObjectMapper.
}

Exception handling in spring mvc

Which is the best way to capture a exception in spring mvc. I am not getting the end to end implementation of the exception handling in spring mvc.
I have implemented #ControllerAdvice. Can you please confirm whether I have implemented in right way to handle the exception.
Question:
How can I handle the service layer exception. Do I have to throw it to controller and then to UI? How it works.
How I can handle the sql exception in DAO layer and other exception like Numberformat exception?
Code:
#RequestMapping(value = "/getDepositSearch", method = RequestMethod.POST)
public String depositNumberData(
#ModelAttribute("searchCondition") String searchCondition,
#ModelAttribute("searchText") String searchText,
final RedirectAttributes redirect, Model depositStatus,
HttpServletRequest request) {
String pageForward = null;
try {
List<MRPSDeposit> depositDetails = null;
if (!searchText.isEmpty()) {
depositDetails = mrpsDeposit.getDepositDetails(searchCondition,
searchText);
}
Map<String, String> searchList = new LinkedHashMap<String, String>();
if (searchCondition.equals(ManagementConstants.DEPOSITDATEKEY)) {
searchList.put(ManagementConstants.DEPOSITDATEKEY,
ManagementConstants.DEPOSITDATEVALUE);
} else if (searchCondition.equals(ManagementConstants.DEPOSITNUMBERKEY)) {
searchList.put(ManagementConstants.DEPOSITNUMBERKEY,
ManagementConstants.DEPOSITNUMBERVALUE);
} else {
searchList.put(ManagementConstants.DEPOSITNUMBERKEY,
ManagementConstants.DEPOSITNUMBERVALUE);
searchList.put(ManagementConstants.DEPOSITDATEKEY,
ManagementConstants.DEPOSITDATEVALUE);
}
if (depositDetails.size() == 0) {
redirect.addFlashAttribute("flashMessage",
ManagementConstants.NORECORDFOUND);
pageForward = "redirect:/mrps/getDepositDetails";
} else if (depositDetails.size() > 1) {
Map<String, Map<String, String>> search = new HashMap<String, Map<String, String>>();
search.put("searchContent", searchList);
depositStatus.addAttribute("searchAllContents", search);
depositStatus.addAttribute("depositDetails", depositDetails);
pageForward = "multipleDepositDetails";
} else {
Map<String, Map<String, String>> search = new HashMap<String, Map<String, String>>();
search.put("searchContent", searchList);
depositStatus.addAttribute("searchAllContents", search);
depositStatus.addAttribute("depositDetails", depositDetails);
if (request.isUserInRole("ROLE_READ")) {
pageForward = "readDepositDetails";
} else {
pageForward = "updateDepositDetails";
}
}
} catch (InfoManagementException e) {
System.out.println("weee"+e);
}
return pageForward;
}
Service layer:
#Override
#Transactional(readOnly = true)
public List<MRPSDeposit> getDepositDetails(String searchCondition,
String searchText) {
List<MRPSDeposit> mrpsDepositDetails = new ArrayList<MRPSDeposit>();
/* try { */
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd",
Locale.ENGLISH);
if (searchCondition.equalsIgnoreCase(ManagementConstants.DEPOSITNUMBERKEY)) {
System.out.println("finalal");
mrpsDepositDetails = mrpsDepositDao.findByDepositNumber(
searchCondition, Short.valueOf(searchText));
} else {
try {
mrpsDepositDetails = mrpsDepositDao.findByDepositDate(
searchCondition, formatter.parse(searchText));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return mrpsDepositDetails;
}
DAO layer:
#Override
public List<MRPSDeposit> findByDepositNumber(String searchCondition,
Short searchTxt) {
List<MRPSDeposit> searchResult = super.findByDepositNumber(
searchCondition, searchTxt);
return searchResult;
}
Controller Advice:
#ControllerAdvice
public class GlobalExceptionController {
#ExceptionHandler(InfoManagementException.class)
public ModelAndView handleCustomException(InfoManagementException ex) {
ModelAndView model = new ModelAndView("error/generic_error");
System.out.println();
model.addObject("errCode", ex.getErrCode());
model.addObject("errMsg", ex.getErrMsg());
return model;
}
#ExceptionHandler(Exception.class)
public ModelAndView handleAllException(Exception ex) {
ModelAndView model = new ModelAndView("error/generic_error");
model.addObject("errMsg", "this is Exception.class");
return model;
}
}
How can I handle the service layer exception. Do I have to throw it to
controller and then to UI? How it works.
In both cases that depends on what are your requirements. There are cases when you will need to show the same page with an error message, also there are some cases when you need to redirect to another error page. In other cases probably you don't need to show any error message.
It's common to throw the exception to the controller then process it in the controller advice and show an readable error message on the UI. In the controller advice you can determine the page that will show the message and also log the error message.
How I can handle the sql
exception in DAO layer and other exception like Numberformat
exception?
I would recommed you to use input validation in the controller. If you use it, then you won't get this kind of error. But if you don't have input validation you can throw the exception and show a message on the UI.
Update
You can leave your service layer as you have at this moment and process the exception in the ControllerAdvice. If you want to process the exception in the service layer you can do this with a try/catch.
public void myServiceMethod(){
try{
...
}catch(Exception1 e){//Every catch block can capture a group of exceptions.
//Depending on your business logic, you can throw a new Exception, log it, or do some logic.
logger.log("My error: ", e);
}catch(Exception2 e){//Every catch block can capture a group of exceptions.
throw new MyBusinessException("Something ocurred", e);
}
}
Then in your ControllerAdvice you need to process MyBusinessException and do what you need.

How to send http request parameters using Jersey client

I use the following rest client implementation of jersey to consume a rest service.I am able to do it successfully.Additionally now I need to send request parameters which will be consumed as part of HttpServletRequest on the producer side.
Consumer side Jersey client code
private ClientResponse getWebClientResponse(String RESOURCE_PATH, String methodType, Object requestObj) {
WebResource webResource;
ClientResponse response = null;
try {
String environmentHost = EnvironmentUtil.resolveEnvironmentHost();
Client client = prepareClient();
String RWP_BASE_URI = environmentHost + "/workflow/rest";
webResource = client.resource(RWP_BASE_URI);
WebResource path = webResource.path(RESOURCE_PATH);
if (GET.equals(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(
ClientResponse.class);
} else if (POST.equalsIgnoreCase(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(ClientResponse.class, requestObj);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return response;
}
Producer side
#Context
public void setContext(SecurityContext context) {
this.context = context;
}
public HttpServletRequest getRequest() {
return request;
}
#Context
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public String getSessionUserPID(final HttpServletRequest request,
final SecurityContext context) {
if (request.getSession(false) == null) {
final String exceptionMessage = "getSessionUserPID() failed, session NOT FOUND for this request";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
if (context.getUserPrincipal() == null) {
final String exceptionMessage = "getSessionUserPID() failed, user principal NOT FOUND";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
final String userPID = context.getUserPrincipal().getName();
if (userPID == null || userPID.isEmpty()) {
final String exceptionMessage = "getSessionUserPID() failed, user principal name cannot be null or empty";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
return userPID;
}
The main intention here is currently I get user information from weblogic security context but for a particular scenario I need to pass this part of rest service request and obtain it from HttpServletRequest object.How can I obtain this from httpservletrequest
You can use QueryParam or PathParam in GET method and FormParam in the POST method for sending request parameter to the server.

Play Framework and custom http headers. How to?

I need to send custom HTTP header with login information to my play application (play 1.2.5). That custom header is added by filter.
Problem is that play always throws NullPointerException when I attempt to read:
String loggedUser = request.headers.get("loggeduser").value();
I have also a servlet for testing, where following prints vale from header correctly.
out.println(request.getHeader("loggeduser"));
Am I missing something in play?
Thanks
EDIT: This is my filter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
CustomHeaderWrapper wrapper = new CustomHeaderWrapper((HttpServletRequest) request);
String username = ((HttpServletRequest) request).getRemoteUser();
wrapper.addHeader("loggeduser", username);
chain.doFilter(wrapper, response);
}
And CustomHeaderWrapper:
private Map<String, String> customHeaderMap = null;
public CustomHeaderWrapper(HttpServletRequest request) {
super(request);
customHeaderMap = new HashMap<String, String>();
}
#Override
public String getHeader(String name) {
String header = super.getHeader(name);
return (header != null) ? header : this.getParameter(name);
}
#Override
public Enumeration getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
names.addAll(Collections.list(super.getParameterNames()));
return Collections.enumeration(names);
}
#Override
public String getParameter(String name) {
String paramValue = super.getParameter(name); // query Strings
if (paramValue == null) {
paramValue = customHeaderMap.get(name);
}
return paramValue;
}
public void addHeader(String headerName, String headerValue) {
customHeaderMap.put(headerName, headerValue);
}
I created a little test project, and used the line of code from your question. It works perfectly. I used the Dev HTTP Client plugin for Chrome to set the header.
Remember that all headers are converted to lowercase, before they are added to the request.headers hashmap. So if you placed "loggedUser" inside request.headers.get(), it would never work.

Resources