In the following code I want to return a list of users from their training using ResponseEntity :
public Utilisateur initUserByFormation(Integer idFrormation) {
Utilisateur user = new Utilisaateur() ;
user = userService.getuserByIdFormation(idFrormation) ;
return user;
}
and the controller call this method :
#RequestMapping(value = "/test/{idFrormation}", method=RequestMethod.GET)
public ResponseEntity <List<Utilisateur>> test(#PathVariable("idFrormation") Integer idFrormation) {
List<Utilisateur> utilisateurs = (List<Utilisateur>) userService.initUserByFormation(idFrormation);
return new ResponseEntity <List<Utilisateur>> (utilisateurs, HttpStatus.ACCEPTED);
}
However, I get the following error:
500 Internal Server Error ERROR Unique id: 1736346060 Request processing failed; nested exception is java.lang.ClassCastException: org.c3.unedicbase.domain.Demandeur cannot be cast to java.util.List
Can you help me to find the origin of this error?
Thank you in advance.
Related
I have a controller that, in case there is no user with the given name, will return 404 NOT FOUND.
#GetMapping(value = "/profile/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity<User> getUsers(#PathVariable("username") String username) {
User user = userService.findOneByUsername(username);
if(user != null) {
return ResponseEntity.ok(user);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Then I created a controller that will be able to handle this exception
#ControllerAdvice
public class ExceptionHandlerController {
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public ModelAndView handleNotFound(NoHandlerFoundException e) {
return new ModelAndView("redirect:/signIn");
}
}
However, it has no effect. The controller returns the normal default 404 error page. It does not respond to my controller.
EDIT: I set spring.mvc.throw-exception-if-no-handler-found = true, but that also did not help. I'm using Spring Boot.
You're not throwing NoHandlerFoundException in your controller. This way the ControllerAdvice will not run.
I am having trouble while trying to make MockMvc to include the exception message in the response body. I have a controller as follows:
#RequestMapping("/user/new")
public AbstractResponse create(#Valid NewUserParameters params, BindingResult bindingResult) {
if (bindingResult.hasErrors()) throw BadRequestException.of(bindingResult);
// ...
}
where BadRequestException looks sth like this:
#ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "bad request")
public class BadRequestException extends IllegalArgumentException {
public BadRequestException(String cause) { super(cause); }
public static BadRequestException of(BindingResult bindingResult) { /* ... */ }
}
And I run the following test against /user/new controller:
#Test
public void testUserNew() throws Exception {
getMockMvc().perform(post("/user/new")
.param("username", username)
.param("password", password))
.andDo(print())
.andExpect(status().isOk());
}
which prints the following output:
Resolved Exception:
Type = controller.exception.BadRequestException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 400
Error message = bad request
Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Does anybody have an idea on why is Body missing in the print() output?
Edit: I am not using any custom exception handlers and the code works as expected when I run the server. That is, running the application and making the same request to the server returns back
{"timestamp":1423076185822,
"status":400,
"error":"Bad Request",
"exception":"controller.exception.BadRequestException",
"message":"binding failed for field(s): password, username, username",
"path":"/user/new"}
as expected. Hence, there is a problem with the MockMvc I suppose. It somehow misses to capture the message field of the exception, whereas the default exception handler of the regular application server works as expected.
After opening a ticket for the issue, I was told that the error message in the body is taken care of by Spring Boot which configures error mappings at the Servlet container level and since Spring MVC Test runs with a mock Servlet request/response, there is no such error mapping. Further, they recommended me to create at least one #WebIntegrationTest and stick to Spring MVC Test for my controller logic.
Eventually, I decided to go with my own custom exception handler and stick to MockMvc for the rest as before.
#ControllerAdvice
public class CustomExceptionHandler {
#ExceptionHandler(Throwable.class)
public #ResponseBody
ExceptionResponse handle(HttpServletResponse response, Throwable throwable) {
HttpStatus status = Optional
.ofNullable(AnnotationUtils.getAnnotation(throwable.getClass(), ResponseStatus.class))
.map(ResponseStatus::value)
.orElse(HttpStatus.INTERNAL_SERVER_ERROR);
response.setStatus(status.value());
return new ExceptionResponse(throwable.getMessage());
}
}
#Data
public class ExceptionResponse extends AbstractResponse {
private final long timestamp = System.currentTimeMillis();
private final String message;
#JsonCreator
public ExceptionResponse(String message) {
checkNotNull(message, "message == NULL");
this.message = message;
}
}
This likely means that you either didn't handle the exception or you've really left the body empty. To handle the exception either add an error handler in the controller
#ExceptionHandler
public #ResponseBody String handle(BadRequestException e) {
return "I'm the body";
}
or user the global error handler if you're on 3.2 or above
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler
public #ResponseBody String handleBadRequestException(BadRequestException ex) {
return "I'm the body";
}
}
with this the body will be populate, you should populate it with your error message
Updated solution:
If you don't want to do a full integration test but still want to make sure the message is as expected, you can still do the following:
String errorMessage = getMockMvc()
.perform(post("/user/new"))
...
.andReturn().getResolvedException().getMessage();
assertThat(errorMessage, is("This is the error message!");
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.
I am using Spring Boot for a simple REST API and would like to return a correct HTTP statuscode if something fails.
#RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
#ResponseBody
#ResponseStatus( HttpStatus.OK )
public RestModel create(#RequestBody String data) {
// code ommitted..
// how do i return a correct status code if something fails?
}
Being new to Spring and Spring Boot, the basic question is how do i return different status codes when something is ok or fails?
There are several options you can use. Quite good way is to use exceptions and class for handling called #ControllerAdvice:
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
Also you can pass HttpServletResponse to controller method and just set response code:
public RestModel create(#RequestBody String data, HttpServletResponse response) {
// response committed...
response.setStatus(HttpServletResponse.SC_ACCEPTED);
}
Please refer to the this great blog post for details: Exception Handling in Spring MVC
NOTE
In Spring MVC using #ResponseBody annotation is redundant - it's already included in #RestController annotation.
One of the way to do this is you can use ResponseEntity as a return object.
#RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
public ResponseEntity<?> create(#RequestBody String data) {
if(everything_fine) {
return new ResponseEntity<>(RestModel, HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
A nice way is to use Spring's ResponseStatusException
Rather than returning a ResponseEntityor similar you simply throw the ResponseStatusException from the controller with an HttpStatus and cause, for example:
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cause description here");
This results in a response to the client containing the HTTP status:
{
"timestamp": "2020-07-09T04:43:04.695+0000",
"status": 400,
"error": "Bad Request",
"message": "Cause description here",
"path": "/test-api/v1/search"
}
Note: HttpStatus provides many different status codes for your convenience.
In case you want to return a custom defined status code, you can use the ResponseEntity as here:
#RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
public ResponseEntity<?> create(#RequestBody String data) {
int customHttpStatusValue = 499;
Foo foo = bar();
return ResponseEntity.status(customHttpStatusValue).body(foo);
}
The CustomHttpStatusValue could be any integer within or outside of standard HTTP Status Codes.
Try this code:
#RequestMapping(value = "/validate", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<ErrorBean> validateUser(#QueryParam("jsonInput") final String jsonInput) {
int numberHTTPDesired = 400;
ErrorBean responseBean = new ErrorBean();
responseBean.setError("ERROR");
responseBean.setMensaje("Error in validation!");
return new ResponseEntity<ErrorBean>(responseBean, HttpStatus.valueOf(numberHTTPDesired));
}
There are different ways to return status code,
1 : RestController class should extends BaseRest class, in BaseRest class we can handle exception and return expected error codes.
for example :
#RestController
#RequestMapping
class RestController extends BaseRest{
}
#ControllerAdvice
public class BaseRest {
#ExceptionHandler({Exception.class,...})
#ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorModel genericError(HttpServletRequest request,
HttpServletResponse response, Exception exception) {
ErrorModel error = new ErrorModel();
resource.addError("error code", exception.getLocalizedMessage());
return error;
}
I think the easiest way is to make return type of your method as
ResponseEntity<WHATEVER YOU WANT TO RETURN>
and for sending any status code, just add return statement as
return ResponseEntity.status(HTTP STATUS).build();
For example, if you want to return a list of books,
public ResponseEntity<List<books>> getBooks(){
List<books> list = this.bookService.getAllBooks();
if(list.size() <= 0)
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
else
return ResponseEntity.of(Optional.of(list));
}
I am getting error in my controller Saying Null Pointer Exception while When I don't perform the testing. Everything works fine.
Controller :
#RequestMapping(value = "/studentinsection/{sectionId}", method = RequestMethod.GET)
public ModelAndView studentInSectionForm(#ModelAttribute("studentInSectionFormData") StudentInSectionForm studentInSectionFormData,
#PathVariable Integer sectionId,
ModelMap model) {
ArrayList<StudentInSections> studentInSectionList = (ArrayList<StudentInSections>)
studentInSectionsService.retrieveAllStudentInSections(sectionId, 1);
StudentSection studentSection = studentSectionService.retrieveStudentSection(sectionId);
logger.info("section Name is:" + studentSection.getSectionName());
ArrayList<User> userList = new ArrayList<User>();
for (StudentInSections studentInSections : studentInSectionList) {
String studentName =
(userService.retrieveUserName(studentInSections.getStudentId(), 1));
User users = userService.retrieveUser(studentName);
userList.add(users);
}
logger.info("sectionId is " + sectionId);
ArrayList<User> allStudents = (ArrayList<User>)
userService.retrieveAllStudents();
studentInSectionFormData.setStudentInSectionList(studentInSectionList);
model.addAttribute("studentList", allStudents);
model.addAttribute("userList", userList);
model.addAttribute("studentSectionName", studentSection.getSectionName());
model.addAttribute("studentSectionId", studentSection.getSectionId());
return new ModelAndView("studentinsection", "studentInSectionFormData", studentInSectionFormData);
}
Testing is as follow:
#Test
public void testStudentInSectionForm() throws Exception {
mockMvc.perform(get("/studentinsection/1"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("studentinsection"));
}
this is passing everything into the controller fine even sectionId is getting printed 1 in logger than also studentin sectionList returns nullMointerException. help me to resolve my problem.. Thanx
It slooks like the context is not being loaded correctly. What is the exception stacktrace.
You can also view the request if you do :
mockMvc.perform(get("/studentinsection/1"))
.andExpect(status().isFound())
.andDo(print())