Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Exception Messages with Spring framework

I am using spring and Hibernate in my application,There is one scenario where i insert same records morethan once ,So application correctly throwing Constraint Exception because i applied Unique constraint in one of the db column.So far is everything fine.

But i have to display some custom message like "record already exists'" instead of showing Hibernate Exception.

How can i do with Spring framework.

Any hints or examples greatly appreciated.

Regards,

Raju

like image 775
Raj Avatar asked Aug 27 '11 22:08

Raj


2 Answers

Yes you can exception in controller:

  @ExceptionHandler(Exception.class)
      public ModelAndView handleMyException(Exception  exception) {
         ModelAndView mv = new ModelAndView("error");
         mv.addObject("message"."record already exists");
         return mv;
              } 

Of cause you can catch any tpe of exception just insert it as the parameter to @ExceptionHandler

Hope it helps.

like image 192
danny.lesnik Avatar answered Sep 28 '22 03:09

danny.lesnik


I am facing the same issue but in my case either one or several fields can be duplicated (username or email). Hence the org.hibernate.exception.ConstraintViolationException is not specific enough to say whether the username or email caused this exception to be thrown and what message to display in consequence.

I just looked at danny.lesnik's answer but it's not great as it simply redirects to a "dedicated" page. Assuming you simply redirect to the page user was on would avoid the creation of a new page you'd say. However I assume you already have a Spring validator doing some form validation work. That's why in my case I decided to simply do my fields (username and email) duplication checks in the same place (in the Validator). Seems like a more suitable, consistent (located with the rest of the validation) and cleaner solution.

Here is some code to illustrate:

My Controller

@Controller
public class WebController {

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private CustomUserDetailsValidator customUserDetailsValidator;

    ...
    @RequestMapping(value = "/login/create-account", method = RequestMethod.POST)
    public String createAccount(@ModelAttribute("user") CustomUserDetails user, BindingResult result, Model model, SessionStatus status) {

        customUserDetailsValidator.validate(user, result);

        if(result.hasErrors()){
            model.addAttribute("user", user);

            // Print the errors to the console - FIXME: log error instead
                System.out.println("Validation errors:");
                for (FieldError error : result.getFieldErrors()) {
                    System.out.println(error.getField() + " - " + error.getDefaultMessage());
            }

            return "login/create-account";
        }
        else{
            userService.registerUser(user);             
            return "redirect:/login/create-account-success";
        }
    }
    ...
}

My Validator

public class CustomUserDetailsValidator implements Validator {

    @Autowired
    private UserServiceImpl userService;
    ...

    @Override
    public void validate(Object target, Errors errors) {

        // some simple validations

        // and here some complex validation (is username or email used duplicated?)
        if(errors.getAllErrors().size() == 0){

            if ( userService.doesUsernameAlreadyExist( user.getUsername() ) )
                errors.rejectValue(usernameFieldName, "duplicate.username","username already exists");

            if ( userService.doesEmailAlreadyExist( user.getEmail() ) )
                errors.rejectValue(emailFieldName, "duplicate.email","email already exists");

        }
    }
}

I'm unsure if that's the best way to do this but thought my solution would allow more extension (you can add various checks on any other constraint).

Hope it helps others and it'd also be interesting to get more devs' thought on this solution.

like image 42
Adrien Be Avatar answered Sep 28 '22 02:09

Adrien Be