Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically replace Spring's NumberFormatException with a user-friendly text?

I am working on a Spring web app and i have an entity that has an Integer property which the user can fill in when creating a new entity using a JSP form. The controller method called by this form is below :

@RequestMapping(value = {"/newNursingUnit"}, method = RequestMethod.POST)
public String saveNursingUnit(@Valid NursingUnit nursingUnit, BindingResult result, ModelMap model) 
{
    boolean hasCustomErrors = validate(result, nursingUnit);
    if ((hasCustomErrors) || (result.hasErrors()))
    {
        List<Facility> facilities = facilityService.findAll();
        model.addAttribute("facilities", facilities);

        setPermissions(model);

        return "nursingUnitDataAccess";
    }

    nursingUnitService.save(nursingUnit);
    session.setAttribute("successMessage", "Successfully added nursing unit \"" + nursingUnit.getName() + "\"!");
    return "redirect:/nursingUnits/list";
}

The validate method simply checks if the name already exists in the DB so I did not include it. My issue is that, when I purposely enter text in the field, I would like to have a nice message such as "The auto-discharge time must be a number!". Instead, Spring returns this absolutely horrible error :

Failed to convert property value of type [java.lang.String] to required type [java.lang.Integer] for property autoDCTime; nested exception is java.lang.NumberFormatException: For input string: "sdf"

I fully understand why this is happening but i cannot for the life of me figure out how to, programmatically, replace Spring's default number format exception error message with my own. I am aware of message sources which can be used for this type of thing but I really want to achieve this directly in the code.

EDIT

As suggested, i built this method in my controller but i'm still getting Spring's "failed to convert property value..." message :

@ExceptionHandler({NumberFormatException.class})
private String numberError()
{
   return "The auto-discharge time must be a number!";
}

OTHER EDIT

Here is the code for my entity class :

@Entity
@Table(name="tblNursingUnit")
public class NursingUnit implements Serializable 
{
private Integer id;
private String name;
private Integer autoDCTime;
private Facility facility;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() 
{
    return id;
}

public void setId(Integer id) 
{
    this.id = id;
}

@Size(min = 1, max = 15, message = "Name must be between 1 and 15 characters long")
@Column(nullable = false, unique = true, length = 15)
public String getName() 
{
    return name;
}

public void setName(String name) 
{
    this.name = name;
}

@NotNull(message = "The auto-discharge time is required!")
@Column(nullable = false)
public Integer getAutoDCTime() 
{
    return autoDCTime;
}

public void setAutoDCTime(Integer autoDCTime) 
{
    this.autoDCTime = autoDCTime;
}

@ManyToOne (fetch=FetchType.EAGER)
@NotNull(message = "The facility is required")
@JoinColumn(name = "id_facility", nullable = false)
public Facility getFacility()
{
    return facility;
}

public void setFacility(Facility facility)
{
    this.facility = facility;
}

@Override
public boolean equals(Object obj) 
{
    if (obj instanceof NursingUnit)
    {
        NursingUnit nursingUnit = (NursingUnit)obj;
        if (Objects.equals(id, nursingUnit.getId()))
        {
            return true;
        }
    }
    return false;
}

@Override
public int hashCode() 
{
    int hash = 3;
    hash = 29 * hash + Objects.hashCode(this.id);
    hash = 29 * hash + Objects.hashCode(this.name);
    hash = 29 * hash + Objects.hashCode(this.autoDCTime);
    hash = 29 * hash + Objects.hashCode(this.facility);
    return hash;
}

@Override
public String toString()
{
    return name + " (" + facility.getCode() + ")";
}
}

YET ANOTHER EDIT

I am able to make this work using a message.properties file on the classpath containing this :

typeMismatch.java.lang.Integer={0} must be a number!

And the following bean declaration in a config file :

@Bean
public ResourceBundleMessageSource messageSource() 
{
    ResourceBundleMessageSource resource = new ResourceBundleMessageSource();
    resource.setBasename("message");
    return resource;
}

This gives me the correct error message instead of the Spring generic TypeMismatchException / NumberFormatException which i can live with but still, I want to do everything programmatically wherever possible and I'm looking for an alternative.

Thank you for your help!

like image 359
Martin Avatar asked Feb 06 '18 18:02

Martin


People also ask

How do I fix NumberFormatException for input string?

For example, this exception occurs if a string is attempted to be parsed to an integer but the string contains a boolean value. Since the NumberFormatException is an unchecked exception, it does not need to be declared in the throws clause of a method or constructor. It can be handled in code using a try-catch block.

How do I resolve number format exception?

To handle this exception, try–catch block can be used. While operating upon strings, there are times when we need to convert a number represented as a string into an integer type. The method generally used to convert String to Integer in Java is parseInt().

What is NumberFormatException in Java with example?

There may be a mismatch between the input string and the type of the method which is being used for parsing. If you provide the input string like "1.0" and you try to convert this string into an integer value, it will throw a NumberFormatException exception. Example- Integer. parseInt("1.. 0");

How do you prevent number format exception in Java?

We can keep the code which is throwing exception into try block. try{ int i = Integer. parseInt(input); }catch(NumberFormatException ex){ // handle your exception ... }


2 Answers

You may be able to override that messaging by providing an implementation of the Spring DefaultBindingErrorProcessor similar to what is done here: Custom Binding Error Message with Collections of Beans in Spring MVC

like image 198
Joe W Avatar answered Oct 23 '22 23:10

Joe W


You can annotate a method with:

@ExceptionHandler({NumberFormatException.class})
public String handleError(){
   //example
   return "Uncorrectly formatted number!";
}

and implement whatever you want to do in case the exception of that type is thrown. The given code will handle exceptions happened in the current controller. For further reference consult this link.

To make global error handling you can use @ControllerAdvice in the following way:

@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {

   @ExceptionHandler({NumberFormatException.class})
    public String handleError(){
       //example
       return "Uncorrectly formatted number!";
    }
} 
like image 2
NiVeR Avatar answered Oct 23 '22 22:10

NiVeR