"error": "Method Not Allowed", "trace": "org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported - spring-boot

I am trying to check my #RestController with Postman but when I enter localhost:8081/rest/teachers/remove/2 I gain this error
My RestController :
#RestController
#RequestMapping("/rest/teachers")
public class TeacherRestController {
private static final String TEACHER_MODEL = "teacher";
#Autowired
TeacherService teacherService;
#DeleteMapping("/remove/{id}")
public ResponseEntity<HttpStatus> deleteTeacher(#PathVariable("id") long id) {
try {
teacherService.removeTeacher(teacherService.getTeacherById((int) id));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}

It is my foolish mistake.
I sent "GET" request on the Postman.
When I switched it to "Delete", it worked.

Related

Spring boot #Valid is not returning proper message

Controller Method
#PostMapping("/hello")
public Hello hello(#Valid #RequestBody Hello hello) {
return hello;
}
POJO
import jakarta.validation.constraints.NotBlank;
class Hello{
#NotBlank(message = "msg must be present")
String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
Upon hitting the above URL with the following payload
{
"msg":""
}
I am getting the following response.
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Invalid request content.",
"instance": "/hello"
}
It should ideally specify the message msg must be present.
What's wrong here?
The following things have been already tried
added server.error.include-message: always in application.properties file
#ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException e) {
return new ResponseEntity<Object>("ConstraintViolationException",
HttpStatus.BAD_REQUEST);
}
Thanks in advance 👏
Edit
I had a #RestControllerAdvice and it starts working fine, once i remove it. #RestControllerAdvice is needed in my case for the customization of exceptions.
You have to write a controller advice and return the interpolated message from the exception caught in handler for invalid method argument.
#RestControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
String bodyOfResponse = ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
return new ResponseEntity(bodyOfResponse, HttpStatus.BAD_REQUEST);
}
}
And after that you should get back message msg must be present along with 400. In case you have more constraints, you should iterate over field errors, and get(0) is only for demonstration purpose.

Why to use #ResponseBody with #ControllerAdvice in the case of RESTServices

I am learning about global exception handling in spring boot. I have a designed a controller annotated with #RestController which has a controller method that throws an exception. I have designed another class named GlobalExceptionHandling annotated with #RestControllerAdvice/#ControllerAdvice. It works fine and handles the exception when annotated with #RestControllerAdvice but doesn't work as expected when annotated with #ControllerAdvice. I am sharing my code and the responses i got on postman.
DemoController:
#RestController
public class DemoController {
#RequestMapping("exception/arithmetic")
public String controllerForArithmeticException()
{
throw new ArithmeticException("Divide by zero error");
}
#RequestMapping("exception")
public String controllerForException() throws Exception
{
throw new Exception("An exception occurred");
}
}
GlobalExceptionHandler: (with #RestControllerAdvice)
#RestControllerAdvice
public class GlobalExceptionHandler{
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e)
{
return "Exception: " + e.getMessage();
}
#ExceptionHandler(value = ArithmeticException.class)
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleArithmeticException(ArithmeticException e)
{
return "ArithmeticException: " + e.getMessage();
}
}
Response on postman:
Status: 404 Bad Request
Response Body: ArithmeticException: Divide by zero error
Console: Nothing gets printed on console.
GlobalExceptionHandler: (with #ControllerAdvice)
#ControllerAdvice
public class GlobalExceptionHandler{
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e)
{
return "Exception: " + e.getMessage();
}
#ExceptionHandler(value = ArithmeticException.class)
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleArithmeticException(ArithmeticException e)
{
return "ArithmeticException: " + e.getMessage();
}
}
Response on postman:
Status: 404 Bad Request
Response Body: {
"timestamp": "2020-02-15T12:41:40.988+0000",
"status": 404,
"error": "Not Found",
"message": "Divide by zero error",
"path": "/exception/arithmetic"
}
Console: Nothing gets printed on console.
Can you explain what exactly #ResponseBody do?

Spring boot custom exception not getting printed in logs

I am trying to implement a custom exception for my Spring boot REST project. The custom exception gets called but shows no impact in the way error message is displayed.
This is the POJO I'm using for my custom errors:
public class ApiError {
private HttpStatus status;
private String message;
private List<String> errors;
public ApiError(HttpStatus status, String message, List<String> errors) {
super();
this.status = status;
this.message = message;
this.errors = errors;
}
public ApiError(HttpStatus status, String message, String error) {
super();
this.status = status;
this.message = message;
errors = Arrays.asList(error);
}
}
This is the exception handler I wrote:
#ControllerAdvice
#EnableWebMvc
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
System.out.println("Custom exception!!");
//List<String> details = new ArrayList<>();
//details.add(ex.getLocalizedMessage());
//System.out.println("Localize message:: "+ex.getLocalizedMessage());
// ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(),
//request.getDescription(false));
ApiError error = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR,"Server Error", request.getDescription(false));
return new ResponseEntity<Object>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Additionally, I'm defined the following method within my controller:
#RequestMapping(value = "/model", params = "number", method = RequestMethod.GET, produces = "application/json")
List<Model> getModel(HttpServletRequest request,#RequestParam(value = "codeNumber") String number) throws Exception{
List<Model> model = null;
try {
model = niiService.getModel(number);
}catch(RuntimeException e){
new Exception(e);
}
return model;
}
However, in stead of my custom POJO, I'm seeing the following exception:
{
"timestamp": 1547013989124,
"status": 500,
"error": "Internal Server Error",
"message": "Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure\n\nThe last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.",
"path": "/model"
}
I was expecting the following JSON structure in stead:
{
"status": 500,
"message": "Server Error"
..
}
Please let me know, what I am missing to get the error response in the way I wanted.
You are missing the throw in front of the custom exception.
Also make sure that you are catching the right exception inside your controller.
Change
catch (RuntimeException e) {
//custom exception
new Exception(e);
}
To
catch (RuntimeException e) {
//custom exception
throw new Exception(e);
}
I missed adding getter and setter to APIError class. Hence, the response was not coming in the way I expected.

File upload Restful API: Spring-boot

I'm trying to make image uploading but I get this error, and I don't know why. I've already tried many things but I'm still getting errors.
Firstly, this:
{
"timestamp": 1454645660390
"status": 405
"error": "Method Not Allowed"
"exception": "org.springframework.web.HttpRequestMethodNotSupportedException"
"message": "Request method 'POST' not supported"
"path": "/usuarios/update"
}
This is my controller:
Note: returns null for testing.
#RequestMapping(value = "/update", method = RequestMethod.POST, headers = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Usuarios> updateUsuario(
OAuth2Authentication authentication,
HttpServletRequest req,
#RequestBody Usuarios usuarios,
#RequestParam("file") MultipartFile file) {
req.getHeaderNames();
file.getName();
return null;
}
And this is my MultipartResolver:
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(1000000);
return resolver;
}
Any suggestions what I'm doing wrong? Thank you so much!
UPDATE
I've updated my #Bean:
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class TierraApplication {
public static void main(String[] args) {
SpringApplication.run(TierraApplication.class, args);
}
#Bean
public MultipartConfigElement multipartConfigElement() {
return new MultipartConfigElement("");
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(1000000);
return resolver;
}
}
and the method on my #RestController:
#RestController
#RequestMapping("/usuarios")
public class UsuariosController implements Serializable {
#RequestMapping(value = "/update", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
public ResponseEntity<Usuarios> updateUsuario(
#RequestBody Usuarios usuarios,
#RequestParam("file") MultipartFile file) {
file.getName();
return null;
}
}
but now i'm getting this error:
{
"timestamp": 1454683574928
"status": 415
"error": "Unsupported Media Type"
"exception": "org.springframework.web.HttpMediaTypeNotSupportedException"
"message": "Content type 'multipart/form-data;boundary=----WebKitFormBoundary6GTTqiBmiacyW0xb;charset=UTF-8' not supported"
"path": "/usuarios/update"
}
EDIT 2
Ok, I've deleted the #Bean of multipartResolver and #RequestBody and all works fine.
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ResponseEntity<?> updateUsuario(#RequestParam("file") MultipartFile file,
OAuth2Authentication authentication,
HttpServletRequest req) {
try {
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(name, HttpStatus.OK);
}
But now I can't reach my body in the request. If I put it got again all the same errors. So how can I pass or reach the body with a JSON like this?
{
"idUsuario": 1,
"roles":{"idRol": 1, "nombreRol": "ADMINISTRADOR", "fechaCreacion": "2016-01-31", "fechaModificacion": null,…},
"nombre": "User",
"apellido": "Test",
"fechaNacimiento": "1992-04-04",
"dni": 38078020,
"email": "test#hotmail.com",
"telefono": 155797919,
"domicilio": "test 972",
"provincia": "San Salvador de Jujuy",
"username": "tester",
"imagen": null,
"estado": true,
"fechaCreacion": "2016-02-03",
"fechaModificacion": null,
"idUsuarioCreacion": 1,
"idUsuarioModificacion": 0,
"passwordUsuario": "$2a$10$SGueYkRnMkL43Ns1nmA9NeONLLrqjChHtYwO8eh/LrMJlTkFHielW"
}
OK. That's the problem.
#RestController("/usarios")
sets the name of the controller not the urlmapping. You should annotate you class with
#RestController
#RequestMapping("/usarios")
to set the correct urlmapping for your service.

Throw exception from spring controller which producces xml MediaType

I have the the following controller with one RequestMapping which produces an xml MediaType.
#RestController
#RequestMapping("/api")
public class ArticleResource {
#RequestMapping(value = "/xml/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<byte[]> getXml(#PathVariable(value = "id") String id,
final HttpServletRequest request,
final HttpServletResponse response) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(path + id + ".xml");
} catch (FileNotFoundException e) {
throw new BadRequestException("No such xml exists");
}
try {
return new ResponseEntity<byte[]>(IOUtils.toByteArray(inputStream), HttpStatus.OK);
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
}
}
The BadRequestException implementation is the following:
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
It works fine when the xml exists, but when the xml cannot be found I have a 406 error code. I suppose the problem occurs because it expects a xml media type and instead a RuntimeException is returned. How can I tackle with this issue?
Do you have an Accept: header in your HTTP request? Your error handler will just return an HTTP error code (response status) so it causes a 406 Not Acceptable on the client side if the client expects XML.
If this is the case you can return an XML response entity from the error handler and update your signature to reflect that it produces XML. Or you can try removing the Accepts from your request.
I solved my issue by returning the following:
String returnString = "XML file don't exists";
return new ResponseEntity<byte[]>(IOUtils.toByteArray(
new ByteArrayInputStream(returnString.getBytes())), HttpStatus.NOT_FOUND);

Resources