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!