Catching the IllegalArgumentException thrown by PropertyEditors in Spring - java

I have a PropertyEditor in order to translate ids into Persons, with it's setAsText (String text) as follows:
public void setAsText(String text) throws IllegalArgumentException {
try {
int id = Integer.parseInt(text);
Person person = peopleService.get(id);
this.setValue(person);
}
catch (NumberFormatException ex) {
// ...
throw new IllegalArgumentException("Not a number!: " + text);
}
catch (PersonNotFoundExcetion ex) {
// ...
throw new IllegalArgumentException("Impossible to get Person: " + text);
}
}
And my PeopleController has a method as follows:
#RequestMapping("/getPerson")
public void ver (#RequestParam Person person, Model model) {
model.addAttribute (person);
// ...
}
I want to catch the IllegalArgumentException in order to show a friendly message to the user, such as "Sorry, the Person you are looking for isn't here", but I don't know where to do that...
Thanks!

General exception handling can be done in this way:
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleAllExceptions(Exception e) {
return "redirect:/error.html"; /* use the correct view name */
}
More specfic you could use BindingResult
#RequestMapping(value = "/datedata", method = RequestMethod.POST)
public String create(
#ModelAttribute("datedata") final DateData datedata,
final BindingResult result) {
if (result.hasErrors()) {
return "datedata/create";
} else {
...
return "myView";
}
}
But I guess this works only for "Forms" (ModelAttribute)
In my humble opinion it is not a good idea to let Spring handle validaten of user input by property editors. I would strongly recommend to use the Form way: Build a command object with a STRING field an use a validator on it.

The exception ought to be caught in the Controller. It should never leak out to the view and end user.
If this is a web app, I'd recommend using the validation and binding API rather than PropertyEditor. That will allow you to return Errors that you can use to tell the UI what needs to be corrected.
Your exception handling needs work. I would not recommend catching an exception and doing nothing other than wrapping it and re-throwing. That's not handling anything or adding new information. It's actually less information as coded.

Related

How to check or throw user defined exception for value which is not there in ENUM , Let say I passes Metadata= "DF" from postman

public enum Metadata{
AC, CD;
}
I am getting json parser error when passing value which is not there in enum..and that error is very lengthy and not readable to user ..instead I should get a proper readable message but I dont know how to resolve this error
instead I should get a proper readable message
Then you need to implement a method that would validate the input and in the case if provided enum-name doesn't exist it would throw an exception with a suitable message.
That's how it might look like:
public enum Metadata{
AC, CD;
public static Metadata get(String name) {
if (!isValid(name)) throw new MyExceptoin("message");
return valueOf(name);
}
public static boolean isValid(String name) {
return Arrays.stream(values()).anyMatch(e -> e.name().equals(name));
}
}
It would be more cleaner approach than catching an IllegalArgumentException (because it's a runtime exception) that can be thrown valueOf(), and then throwing a desired exception from the catch block. And you can't gain a significant performance advantage with this approach since there will be only a few enum-members.
Just for illustrative purposes, that's how an exception can be caught and rethrowing:
public static Metadata get(String name) {
try {
return valueOf(name);
} catch (IllegalAccessException e) {
throw new MyExceptoin("message");
}
}

How to handle a PSQLException in java?

I have a unique constraint on one of my entities and whenever I get a PSQLException which occurs whenever that constraint is violated, I want to respond with a bad request.
This is my exception handler which I tried to implement:
#ControllerAdvice
public class DatabaseExceptionHandler {
#ExceptionHandler(value = PSQLException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleDatabaseExceptions(PSQLException e) {
// i want to respond with a bad request only when this condition is satisfied
//
// if (e.getSQLState().equals("23505")) {
//
// }
}
}
And this is where the model is saved in db:
public DepartmentForHoliday setDepartment(DepartmentForHoliday department) {
if (department.getDepartmentId() == null) {
Department savedDepartment = new Department();
savedDepartment.setName(department.getName());
try {
departmentRepository.save(savedDepartment);
} catch (PSQLException e) {
/*here i have a compiler error which says that this exception is never thrown in the corresponding try block, but where ?*/
}
}
This is the exception that is thrown when I add a duplicate entry:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_1t68827l97cwyxo9r1u6t4p7d"
Detail: Key (name)=(Tech) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458) ~[postgresql-9.4.1211.jre7.jar:9.4.1211.jre7]
How to handle PSQLExceptions ? Should I make my own exception as a wrapper or how to solve this problem ?
Key problem is that PSQLException is wrapped into some Spring exception (which I assume from your code); you have to unwrap it (for example using guava's Throwables):
public DepartmentForHoliday setDepartment(DepartmentForHoliday department) {
if (department.getDepartmentId() == null) {
Department savedDepartment = new Department();
savedDepartment.setName(department.getName());
try {
departmentRepository.save(savedDepartment);
} catch (RuntimeException e) {
Throwable rootCause = com.google.common.base.Throwables.getRootCause(e);
if (rootCause instanceof SQLException) {
if ("23505".equals(((SQLException) rootCause).getSQLState())) {
// do smth interesting :)
}
}
}
}
}
Once you do that you can throw your custom exception and handle it in DatabaseExceptionHandler
You are catching PSQLException. Instead of that, please catch SQLException. With SQLException you will can handle all this SQL exceptions.
You can check the SQLException knowledge at this link
Then in your code just treat the SQLException as you want. The most generic catch clause is the following one:
catch (SQLException e)
{
System.out.println("ERROR: Fetch statement failed: " +
e.getMessage());
}
With this code you are printing the exception. If you want more information, check this
This is quite late, but building on previous responses I was able to solve it as so:
try {
return this.projectRepository.saveAndFlush(patchedProjectEntity);
} catch (DataIntegrityViolationException e) {
if (e.getMostSpecificCause().getClass().getName().equals("org.postgresql.util.PSQLException") && ((SQLException) e.getMostSpecificCause()).getSQLState().equals("23505"))
throw new UniqueConstraintViolationException("", e.getMostSpecificCause());
throw e;
}
Where UniqueConstraintViolationException is a custom exception and handled with a spring controller advice.
You might as well register an exception handler for that wrapped exception (that #radek mentioned) directly.
In your case that's:
#ExceptionHandler(DataIntegrityViolationException::class)
protected fun handleDataIntegrityException(ex: DataIntegrityViolationException, request: WebRequest) : ResponseEntity<SomeBody>{
return ResponseEntity.badRequest().body(someBodyHere)
}
The error is converted within convertHibernateAccessException in org.springframework.orm.jpa.vendorHibernateJpaDialect, which has already processed away from PSQL. You can add a breakpoint there and follow the stacktrace.
There is a lot of proxy'ing happening under the hood, but the takeaway is that there is always a readable, expressive Exception to use directly.

Return warnings as well as errors from Spring MVC?

I'm looking for a way to return non-fatal validation "warning" messages for display on a JSP form (in addition to the usual validation "error" messages). These would be messages that allow processing to continue instead of blocking the completion of a task.
I'd like to use the existing Spring 4 MVC plumbing for this: The BindingResult object, the Spring Validator interface, and the Spring <form:errors /> tag. But so far I haven't been able to work out the details of returning a second BindingResult object and getting the messages to display.
Here's what I've got so far:
myFormValidator.validate(myForm, bindingResult);
myFormValidator.validateWarnings(myForm, warnings);
model.addAttribute("warnings",warnings);
return new ModelAndView(FORM_VIEW, "myForm", myForm);
But I have no idea how to tie the free-floating BindingResult object warnings to a <form:errors /> tag on the JSP side. Can anyone help with this?
It doesn't look like there's an easy way to do this using the existing <form:errors /> tag. What I wound up doing was creating a custom tag, based off of ErrorsTag.java and its superclasses.
Here is how the tag looks:
<mytag:warnings bind="${warnings}" path="myFieldName" />
This will list all the warnings for myForm.myFieldName in a nicely styled block.
Here are the guts (boilerplate can be obtained from http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/tags/form/AbstractHtmlElementTag.html ):
protected boolean shouldRender() throws JspException {
try {
if (this.getPath() != null &&
this.getPath() != "") {
// Field errors
return (this.bind.hasFieldErrors(this.getPath()));
} else {
// Global errors
return this.bind.hasGlobalErrors();
}
} catch (IllegalStateException ex) {
// Neither BindingResult nor target object available.
return false;
}
}
protected int writeTagContent(TagWriter tagWriter) throws JspException{
if (shouldRender()) {
return doWrite(tagWriter);
}
return BodyTag.SKIP_BODY;
}
protected int doWrite(TagWriter tagWriter) throws JspException {
try {
tagWriter.startTag(getElement());
writeDefaultAttributes(tagWriter);
String delimiter = ObjectUtils.getDisplayString(evaluate("delimiter", getDelimiter()));
List<String> errorMessages = null;
if (this.getPath() != null) {
errorMessages = getFieldErrorMessages(bind.getFieldErrors(this.getPath()));
} else {
errorMessages = getGlobalErrorMessages(bind.getGlobalErrors());
}
tagWriter.appendValue("<ul>");
for (int i = 0; i < errorMessages.size(); i++) {
String errorMessage = errorMessages.get(i);
tagWriter.appendValue("<li>");
tagWriter.appendValue(getDisplayString(errorMessage));
tagWriter.appendValue("</li>");
}
tagWriter.appendValue("</ul>");
tagWriter.forceBlock();
tagWriter.endTag();
} catch (NullPointerException ex) {
ex.printStackTrace();
}
return BodyTag.EVAL_BODY_INCLUDE;
}

Spring MVC: manage BindingException

I have a problem with the binding of a form input text to a Integer field of the bean to which the form is binded. If I write a wrong number in the input text (eg: "12b") I have a Binding Exception. So, I set a #InitBinder in my controller in this way:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Integer.class, new CustomIntegerBinder());
}
Where CustomIntegerBinder is implemented as follows:
public class CustomIntegerBinder extends PropertyEditorSupport {
#Override
public void setAsText(String text) throws IllegalArgumentException {
try {
setValue(Integer.parseInt(text));
} catch (Exception e) {
//I WANT TO ADD ERROR TO THE ERROR LIST!
}
}
#Override
public String getAsText() {
return getValue().toString();
}
}
My question is: how could I succeed in adding a message error to the errors list, so that a conversion error would not cause a crasch of the application, but a message to be printed in the "errors" tag in the jsp?
Thank you!
The setAsText method should throw an IllegalArgumentException (as the method signature indicates) if the value can't be set from text.
If you throw the IllegalArgumentException from your catch then Spring should add the error for you.

How can I print the argument value that caused Exception in Java?

I am writing a parser for csv-files, and sometimes I get NumberFormatException. Is there an easy way to print the argument value that caused the exception?
For the moment do I have many try-catch blocks that look like this:
String ean;
String price;
try {
builder.ean(Long.parseLong(ean));
} catch (NumberFormatException e) {
System.out.println("EAN: " + ean);
e.printStackTrace();
}
try {
builder.price(new BigDecimal(price));
} catch (NumberFormatException e) {
System.out.println("Price: " + price);
e.printStackTrace();
}
I would like to be able to write something like:
try {
builder.ean(Long.parseLong(ean));
} catch (NumberFormatException e) {
e.printMethod(); // Long.parseLong()
e.printArgument(); // should print the string ean "99013241.23"
e.printStackTrace();
}
Is there any way that I at least can improve my code? And do this kind of printing/logging more programmatically?
UPDATE: I tried to implement what Joachim Sauer answered, but I don't know if I got everything right or if I could improve it. Please give me some feedback. Here is my code:
public class TrackException extends NumberFormatException {
private final String arg;
private final String method;
public TrackException (String arg, String method) {
this.arg = arg;
this.method = method;
}
public void printArg() {
System.err.println("Argument: " + arg);
}
public void printMethod() {
System.err.println("Method: " + method);
}
}
The Wrapper class:
import java.math.BigDecimal;
public class TrackEx {
public static Long parseLong(String arg) throws TrackException {
try {
return Long.parseLong(arg);
} catch (NumberFormatException e) {
throw new TrackException(arg, "Long.parseLong");
}
}
public static BigDecimal createBigDecimal(String arg) throws TrackException {
try {
return new BigDecimal(arg);
} catch (NumberFormatException e) {
throw new TrackException(arg, "BigDecimal.<init>");
}
}
}
Example of use:
try {
builder.ean(TrackEx.createBigDecimal(ean));
builder.price(TrackEx.createBigDecimal(price));
} catch (TrackException e) {
e.printArg();
e.printMethod();
}
EDIT: Same question but for .NET: In a .net Exception how to get a stacktrace with argument values
You can easily implement such detailed information on custom-written exceptions, but most existing exceptions don't provide much more than a detail message and a causing exception.
For example you could wrap all your number parsing needs into a utility class that catches the NumberFormatException and throws a custom exception instead (possibly extending NumberFormatException).
An example where the some additional information is carried via the exception is SQLException which has
a getErrorCode() and a getSQLState() method.
Create a method such as private parse (String value, int type) which does the actual parsing work including exception handling and logging.
parse(ean, TYPE_LONG);
parse(price, TYPE_BIG_DECIMAL);
Where TYPE_ is just something to tell the method how it should parse the value.
Similar to another suggestion, you could extract Long.parseLong(ean) into it's own method (either privately within the class or public on another utility sort of class).
This new method would handle any custom logic AND you could test it in isolation. Yay!

Categories

Resources