Exception when i send my form Spring MVC - spring

I want to insert a record to database so this is my controller :
#RequestMapping(value="/ajouter_activite",method = RequestMethod.POST)
public String AddActivity(#ModelAttribute Movement movement, ModelMap model,BindingResult result){
AddActivityValidator actvalidator = new AddActivityValidator();
actvalidator.validate(movement, result);
if(!result.hasErrors()){
boolean n;
n=actservice.addMovement(movement);
if(n==true){model.addAttribute("success","true");}
else {model.addAttribute("echec","true");}
return "/FicheService";}
else{return "/FicheService";
}
}
When i send my form i get this exception :
Etat HTTP 500 - Request processing failed; nested exception is org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String gestion.delegation.controller.FicheServiceController.AddActivity(gestion.delegation.domaine.Movement,org.springframework.ui.ModelMap,org.springframework.validation.BindingResult)]; nested exception is java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!
Where is the wrong with that ?

Try with
public String AddActivity(#ModelAttribute Movement movement, BindingResult result, ModelMap model)
method signature.
see example 17.1 in http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-methods for more info.

Related

How to check Bad request for #Min on request param in spring controller?

I am pretty new to spring controller. I am trying to write unit test for invalid parameter. I have an api that has #RequestParam("id") #Min(1) long id and in my unit test, I pass in "-1". Here is my test:
#Test
public void searchWithInvalidIbId() throws Exception {
mockMvc.perform(get(BASE_URL)
.param(COLUMN_IB_ID, INVALID_IB_ID_VALUE) // = "-1"
.param(COLUMN_TIME_RANGE, TIME_RANGE_VALUE)
.param(COLUMN_TIME_ZONE, TIME_ZONE_VALUE)
.accept(PowerShareMediaType.PSH_DISPATCH_REPORTER_V1_JSON)
.contentType(PowerShareMediaType.PSH_DISPATCH_REPORTER_V1_JSON))
.andExpect(status().isBadRequest());
}
When I run this, I get
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: search.arg2: must be greater than or equal to 1
It makes sense, but I am not sure how to test this is BadRequest. I tried #Test(expected = NestedServletException.class), and it passed, but I don't think it is checking what I want to check. What is the right approach to check this?
You can have your custom exception handler annotated with #ControllerAdvice and handle ConstraintViolationException in that class. You can throw your custom exception with additional details if you wish.
Here is an example approach:
#ControllerAdvice
public class MyCustomExceptionHandler {
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
ApiError constraintViolationException(ConstraintViolationException e) {
return BAD_REQUEST.apply(e.getBindingResult());
}
}
Here ApiError is a custom class to represent your error response, it can be anything else you want. You can add timestamp, http status, your error message etc.

#ExceptionHandler is Not working when automatic binding fails in REST API

I have two REST API's GET POST
When any Exception is thrown inside the method, Exception handler is working fine.
But if i use malformed REST api uri then it only shows 400 Bad Request without going to Exception Handler.
Eg.
If I hit http://localhost:8080/mypojoInteger/abc, it fails to parse string into Integer and hence I am expecting it to go to ExceptionHandler.
It does not go to Exception Handler, Instead I only see 400 Bad Request.
It works fine and goes to Exception Handler when any Exception is thrown inside the GET/POST method.
For eg: It works fine and goes to Exception Handler if I use 123 in path variable
http://localhost:8085/mypojoInteger/123
And change getData method to
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Integer sentNumber) {
throw new NumberFormatException("Exception");
}
NOTE: Same issue is with POST request also.
GET:
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Integer sentNumber) {
//some code
}
POST:
public void postData(#RequestBody MyPojo myPojo) {
//some code
}
Controller Advice class:
#ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(NumberFormatException.class)
protected ResponseEntity<Object> handleEntityNotFound(
NumberFormatException ex) {
// some logic
}
}
How can I handle Exception when it fails to bind String to Integer in REST API uri itself??
EDIT: My Requirement is I should handle the overflow value of integer i.e, If a pass more than maximum value of Integer it must handle it rather than throwing NumberFormatException Stack Trace.
Eg: When i pass over flow value
POJO:
public class MyPojo extends Exception {
private String name;
private Integer myInt;
//getters/setter
}
{
"name":"name",
"myInt":12378977977987879
}
Without #ControllerAdvice it just shows the NumberFormatException StackTrace.
With #ControllerAdvice it just shows 400 bad request with no Response Entity.
I do not want this default stacktrace/400 bad request in case of this scenario
but I want to show my custom message.
The reason that i see is that, because since your request itself is malformed-> the method body never gets executed - hence the exception never occurs because it is only meant to handle the error within the method . It is probably a better design choice for you to form a proper request body rather than allowing it to execute any method so you know the problem before hand.
The issue is because Integer object is not sent as a valid request parameter, example of request: 5 if you send String an exception will be thrown directly. If you want to check if it is a String or Integer you might change your code by following this way:
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Object sentNumber) {
if (!(data instanceof Integer)) {
throw new NumberFormatException("Exception");
}
}
This should work on your example.
Solution:
I found out that I need to handle Bad Request.
So, I have override
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
//Handle Bad Request
}

Calling #PatchMapping annotated method using TestRestController

I have a method annotated with #PatchMapping.
#PatchMapping(path= "/api/transaction/{transaction-id}/return")
public ResponseEntity<Transaction> returnBookTransaction(#PathVariable(name="transaction-id") Long transactionId){
Transaction transaction = transactionRepository.findById(transactionId).get();
transaction.setDateOfReturn(LocalDateTime.now());
return ResponseEntity.ok().body(transaction);
}
I need to test this method. In test method, I need to use TestRestController.patchForObject();
#Test
public void testReturnBookTransaction() throws Exception {
ResponseEntity<Transaction> response = testRestTemplate.patchForObject("/api/transaction/{transaction-id}/return",
, Transaction.class, 1);
Assert.assertEquals(200, response.getStatusCode().value());
}
The code above shows compiler error in template.patchForObject(), as it needs 4 parameters. I don't know, what to pass in 4th parameter.
I just have to pass 1 for {transaction-id}, URL String and return type class, which I have already passed. But this method requires one more parameter as Object.
I don't know, what to pass in Object.
From Spring's documentation:
public T patchForObject(String url,
Object request,
Class responseType,
Map uriVariables)
throws RestClientException
The second argument is for request object. Since you don't have any request-related info in your controller method, you can set it to null.
Try the following:
Transaction response = testRestTemplate.patchForObject("/api/transaction/{transaction-id}/return", null
, Transaction.class, 1);
UPDATE:
If you want to have access to the response entity, try the following:
ResponseEntity<Transaction> response = testRestTemplate.exchange("/api/transaction/{transaction-id}/return", HttpMethod.PATCH, null,Transaction.class, 1);

HTTP Status 500 - Request processing failed; nested exception

Controller:
#RequestMapping(value="/balance.html",method=RequestMethod.GET)
public ModelAndView balance_navigation(#ModelAttribute("command") NetBean netBean,BindingResult result){
System.out.println("controller balance");
//int bal= netservice.displaybalance(cid);
Map<String, Object> model = new HashMap<String, Object>();
System.out.println("controller Map object balance");
model.put("balance", netservice.displaybalance(cid));
System.out.println("controller put() balance");
return new ModelAndView("balance", model);
Dao:
`#Override
public int displaybalance(int cid) {
Session session=sessionFactory.openSession();
System.out.println("query before executed in balance");
Query query=session.createQuery("select accbal from Account as se where se.cid=cid");
////select ACCBAL from Account a join Customer s on a.cid=s.cid where s.cid=cid
System.out.println("query executed in balance");
query.setParameter(0,cid);
return (int) query.list().get(0);`
**org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public org.springframework.web.servlet.ModelAndView com.controller.Netcontroller.balance_navigation(com.bean.NetBean,org.springframework.validation.BindingResult)]; nested exception is java.lang.IllegalStateException: No data type for node: org.hibernate.hql.ast.tree.IdentNode
**
replace your #ModelAttribute("command") to #ModelAttribute("netBean")
same thing jsp also ModelAttribute="netBean"

spring mvc controller Test with Enumeration value

i'm trying to test this Method :
#RequestMapping(value="/PersonalState/{EmployeeId}", method = RequestMethod.PUT)
public #ResponseBody Object Update(#PathVariable Integer EmployeeId, #RequestParam EmployeeState empstate) throws Exception {
EmployeeService.updateEmployeeState(entityManager.find(Employee.class, EmployeeId), empstate);
return null;
}
EmplyeeState is an enumeration , the values are saved in db as integer,this is my test Code:
#Test
public void EmployeeTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.put("/PersonalState/{empstate}",EmplyeeState.PERMANENT)
.param("EmployeeId", "550"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk());
}
I got this Errror:
Resolved Exception:
Type = org.springframework.beans.TypeMismatchException
MockHttpServletResponse:
Status = 400
I tried to pass the two variables as parameters ,passing only the EmployeeId as parameter but i still have the same error besides the param parameters must be both of type String.
Any Idea?
Problem resolved.
i passed as parameter the enum string value.

Resources