public String deleteProduct(#RequestBody String prodId ,HttpServletRequest request ) throws NotLoggedInException {
String userName = (String) request.getSession().getAttribute("user");
System.out.println(userName);
if (userName == null) {
throw new NotLoggedInException("You have not logged in");
}
String userRole = (String) request.getSession().getAttribute("role");
if (!userRole.equalsIgnoreCase("productmaster")) {
throw new AuthorizedUserRoleNotFoundException("you are not authorized to add the products");
}
if(pservice.deleteProduct(prodId))
{
return "Product deleted";
}
return "Product not deleted";
}
Output:
{
"timestamp": "2022-11-20T13:17:24.172+0000",
"status": 400,
"error": "Bad Request",
"message": "Required request body is missing: public java.lang.String"
}
Please tell someone why its showing like this
#Requestbody annotation requires you to pass some request body in json, map form. But you are just passing prodId. I think you should just change #RequestBody annotation.
(#Request Param prodId ,#Requestbody HHttpServletReques request)
The #RequestBody annotation comes with the required attribute defaulting to true. This means that the request should always contain a body, otherwise it will throw an exception. From the error message it appears that your request does not contain a body.
You need to either set the required attribute to false or always provide a body.
Related
I'm trying to understand if it's possible to get the index of invalids objects inside a list that is validated with #Valid.
I already have validation in place where I send a response like this
{
"status": "BAD_REQUEST",
"message": "Validation Error",
"detailedMessage": "There are errors in the entered data",
"timestamp": 1657896844868,
"validationErrors": [
{
"field": "items[0].name",
"message": "The name is mandatory"
},
{
"field": "items[1].surname",
"message": "The surname is mandatory"
}
]
}
The problem is that in the frontend I need to know exactly which objects in the array "items" have problems so I can highlight the corret input. What I'm doing right now is getting the index from the string "items[0].name" using a regex but I really dislike this kind of behavior and I would like to exctract the index of the invalid item and put it in the response.
Ideally I would like to not have the array index but a specific field of the invalid object.
What I mean is that every item has an "id" field and I would like to extract that one and send something like this in response
{
"status": "BAD_REQUEST",
"message": "Validation Error",
"detailedMessage": "There are errors in the entered data",
"timestamp": 1657896844868,
"validationErrors": [
{
"field": "items[12345].name",
"message": "The name is mandatory",
"itemId": 12345
},
{
"field": "items[12346].surname",
"message": "The surname is mandatory",
"itemId": 12346
}
]
}
In this way I would be able to know exactly which object is invalid in the frontend without having to rely on array indexes or regex to extract the index from a string. Of course having the array index as "itemIndex" field would also be better than what I have right now.
Following you can find my request class, that is used in the controller as #Valid #RequestBody, and my ControllerAdvice where I build my response when a MethodArgumentNotValidException happens.
Request
public class Request {
#Valid
#NotEmpty(message = "You must insert at least one item")
private List<#Valid #NotNull Item> items;
}
ControllerAdvice
#RestControllerAdvice
public class BaseExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.BAD_REQUEST, "Validation Error", "There are errors in the entered data");
List<ValidationError> errors = new ArrayList<>();
ex.getBindingResult().getAllErrors().forEach(error -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
ValidationError validationError = new ValidationError(fieldName, errorMessage);
errors.add(validationError);
});
errorResponse.setValidationErrors(errors);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
You can access information about objects that violated the constraint by unwrapping your ObjectError or FieldError to ConstraintViolation (https://docs.oracle.com/javaee/7/api/javax/validation/ConstraintViolation.html).
Here is how you can access array index
Path nodes = error.unwrap(ConstraintViolation.class).getPropertyPath();
for (Path.Node node : nodes) {
if (node.isInIterable()) {
node.getIndex() // for items[12346].surname it will return 123456
}
}
Accessing an element that has thrown an error is also possible using unwrap to ConstraintViolation.
Item item = (Item) error.unwrap(ConstraintViolation.class).getLeafBean(); // don't use cast with no checks in your code
This will return an item which triggered constraint violation.
I try to build my first api. I got problem when i want to register new user. The problem is when i want to send request from postman. I using also SwaggerUI, so when i use Post Request to my end point /registration in SwaggerUI by textfields always i got http status 201 so its works good. Problem is when i want to make Mock to this controller or when i want to send new user in postman request but not always. I show you in example
If i use postman -> post: localhost:8080/registration -> Raw -> JSON
{
"email": "testtest#gmail.com",
"id": 0,
"password": "Test1234567 ",
"username": "testtest"
}
Then i got message
{
"status": "BAD_REQUEST",
"timestamp": "01-03-2021 11:44:26",
"message": "Value cannot be empty!",
"debugMessage": null,
"subErrors": null
}
So its should be good because i used catch exception. But Value isnt empty, so whats happend?I dont know.
But when i go to x-www-form-urlencoded and there i put keys: email, username and password then, user is created!
Another, when im put this same info to Swagger then also my user is created.
Below i add my code from controller and test.
#Test
void shouldCreateNewUser() throws Exception {
UserRegistrationDto user = new UserRegistrationDto( null,"seba12345", "lelelele1908#gmail.com", passwordEncoder.encode("Respeck123"));
mockMvc.perform(post("/registration")
.header("header1", "1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andExpect(status().isCreated());
}
#PostMapping("/registration")
public ResponseEntity<UserRegistrationDto> registerUser(UserRegistrationDto userRegistrationDto) {
HttpHeaders headers = new HttpHeaders();
userService.save(userRegistrationDto);
return new ResponseEntity<>(userRegistrationDto, headers, HttpStatus.CREATED);
}
You need #RequestBody in your controller method to tell Spring that you want the content of the request body:
#PostMapping("/registration")
public void post(#RequestBody MyDTO dto) {
...
}
I have written a code which will throw the following message if the list id specify in the URL didn't find in the db. It should send a json response with error message but i am getting exception class name also with message:
Expected Output from rest API:
{
"code": 404,
"message": "Watchlist dnd was not found"
}
code:
#RolesAllowed({ "admin" })
#Path("/{listId}")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Returns a watchlist.", notes = "")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "The watchlist was returned.", response = Watchlist.class),
#ApiResponse(code = 404, message = "The watchlist was not found.", response = ErrorMessage.class),
#ApiResponse(code = 500, message = "Internal server error.", response = ErrorMessage.class) })
public Watchlist getList(#PathParam("listId") String listId, #HeaderParam("x-access-token") String jwtToken,
#Context SecurityContext sec, #Context final HttpServletResponse response) throws Exception {
final String sourceMethod = "getList";
if (logger.isLoggable(Level.FINER)) {
logger.entering(CLASSNAME, sourceMethod);
}
WatchlistService service = new WatchlistService(cedmPersitence);
Watchlist list = service.getWatchList(listId);
if (logger.isLoggable(Level.FINER)) {
logger.exiting(CLASSNAME, sourceMethod);
}
return list;
}
public Watchlist getWatchList(String listId) throws IOException,NotFoundException{
Watchlist list = new Watchlist();
list.setListId(listId);
if(listId !=null) {
HBasePersistence persistence = new HBasePersistence();
persistence.init("watchlist");
List<WatchlistEntry> watchListEntries = persistence.getWatchlistByListId(listId);
if (watchListEntries == null || watchListEntries.isEmpty()) {
throw new NotFoundException("Watchlist " + listId + " was not found");
}
list.setEntries(watchListEntries);
}
return list;
}
But I am getting this response:
{
"code": 404,
"message": "class com.ibm.cedm.exception.NotFoundException:Watchlist dnd was not found"
}
anybody know why is it so ?
As you can see in the reference:
https://docs.oracle.com/javaee/7/api/javax/ws/rs/NotFoundException.html#NotFoundException-java.lang.String- , when you pass the error message to a NotFoundException, surely the Throwable.getMessage() enrich that message with the class name.
NotFoundException also accepts a Response as parameter, so instead of passing a message you can build the response by passing the Response.
final Response.ResponseBuilder response = Response.status(Response.Status.NOT_FOUND);
response.entity("Watchlist " + listId + " was not found").type("text/plain");
throw new NotFoundException(response.build());
How do I Check the request body is null or empty?
for eg:
#RequestMapping(method = POST, value = "/my/path/here")
public ResponseEntity<MyDTO> update(#Valid #RequestBody MyDTO requestMyDTO){
.......
}
The code above triggers validation in case of " "(which is null) payload but not in case of "{ }" payload.
is there any annotation to do this ? if not how do i achieve this?
You can check for expected member variables in your requestMyDTO:
if (requestMyDTO.getVarA() == null) {
// throw your exception
}
I have the following controller advice to handle the exceptions within my app globally:
#ControllerAdvice
public class ExceptionHandlingController {
// Convert a predefined exception to an HTTP Status code
#ResponseStatus(value=HttpStatus.BAD_REQUEST) // 400
#ExceptionHandler(ConstraintViolationException.class)
public void ConstraintViolationExceptionHandler() {
//Nothing to do
}
}
The code below is the controller, which tries to save an object to the db (in the service layer). The class that object belongs to, has annotations that fail.
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public void create(#RequestBody CustomUserDetails user, HttpServletResponse response) {
logger.debug("User signup attempt with username: " + username);
userDetailsServices.saveIfNotExists(user);
}
I expect the client to receive a 400 response when ConstraintViolationException is thrown.
When the method returns void , no response is returned. When I change it String and return a random text, I get 404 response back.
{
"timestamp": 1495489172770,
"status": 404,
"error": "Not Found",
"exception": "javax.validation.ConstraintViolationException",
"message": "Validation failed for classes [security.model.CustomUserDetails] during persist time for groups [javax.validation.groups.Default, ]\nList of constraint violations:[\n\tConstraintViolationImpl{interpolatedMessage='must match \"^(?!.*\\..*\\..*)[A-Za-z]([A-Za-z0-9.]*[A-Za-z0-9]){8,15}$\"', propertyPath=username, rootBeanClass=class com.boot.cut_costs.security.model.CustomUserDetails, messageTemplate='{javax.validation.constraints.Pattern.message}'}\n]",
"path": "/signup"
}
How can I make this return a simple BAD REQUEST message as it is defined for the #ExceptionHandler.
Note: ConstraintViolationExceptionHandler is hit!