I am facing a weird problem right now with JodaTime DateTimes and a Spring MVC controller. Although I see that the InitBinder-annotated method is invoked, it is without effects, the strings of the test request are not bound to my domain object, as can state the following error message:
org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'eventCommand' on field 'endDate': rejected value [29/03/2015 12:13]; codes [typeMismatch.eventCommand.endDate,typeMismatch.endDate,typeMismatch.org.joda.time.DateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [eventCommand.endDate,endDate]; arguments []; default message [endDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.time.DateTime' for property 'endDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @javax.validation.constraints.NotNull @javax.persistence.Column @org.hibernate.annotations.Type org.joda.time.DateTime for value '29/03/2015 12:13'; nested exception is java.lang.IllegalArgumentException: Invalid format: "29/03/2015 12:13" is too short]
Field error in object 'eventCommand' on field 'startDate': rejected value [28/03/2015 12:13]; codes [typeMismatch.eventCommand.startDate,typeMismatch.startDate,typeMismatch.org.joda.time.DateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [eventCommand.startDate,startDate]; arguments []; default message [startDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.time.DateTime' for property 'startDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @javax.validation.constraints.NotNull @javax.persistence.Column @org.hibernate.annotations.Type org.joda.time.DateTime for value '28/03/2015 12:13'; nested exception is java.lang.IllegalArgumentException: Invalid format: "28/03/2015 12:13" is too short]
Here is the meaningful part of the controller:
@Controller
@RequestMapping("/***/event")
public class EventController {
private static final String COMMAND = "eventCommand";
@Autowired
private EventDao eventDao;
@InitBinder(value = COMMAND)
public void customizeConversions(WebDataBinder binder) {
DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
df.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true));
}
@RequestMapping(value = {
"/new",
"/edit/{id}"
}, method = POST)
public ModelAndView save(@ModelAttribute(COMMAND) @Valid final Event event, final BindingResult result) {
if (result.hasErrors()) {
return populatedEventForm(event);
}
eventDao.saveOrUpdate(event);
return successfulRedirectionView();
}
private ModelAndView successfulRedirectionView() {
return new ModelAndView("redirect:index.jsp");
}
private ModelAndView populatedEventForm(final Event event) {
ModelMap model = new ModelMap(COMMAND, event);
return new ModelAndView("event/form.jsp", model);
}
}
As well as the test request (driven by spring-test-mvc):
@Test
public void when_saving_valid_event_then_routed_to_home() throws Exception {
mvc.perform(post("/***/event/new").
param("title", "zuper title").
param("description", "zuper description").
param("startDate", "28/03/2015 12:13").
param("endDate", "29/03/2015 12:13")).
andExpect(status().isOk()).
andExpect(view().name("redirect:index.jsp"));
}
And the entity:
@Entity
public class Event {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id")
private long id;
@NotBlank
@Length(max = 1000)
@Column(name = "description", nullable = false)
private String description = "";
@NotNull
@Column(name = "start_date", nullable = false)
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime startDate;
@NotNull
@Column(name = "end_date", nullable = false)
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime endDate;
@NotBlank
@Length(max = 255)
@Column(name = "title", nullable = false, unique = true)
private String title = "";
/* setters & getters */
}
If I commit the @InitBinder-annotated method, the result is the same…
I’ve got the same kind of data binding for another entity (with 1 DateTime member) and it works fine.
Any idea what is wrong ?
Thanks in advance,
Rolf
Alright I found the problem, I was exposing my properties directly as DateTime and not as Date as I was doing for my other entity.
Exposing Dates did the trick.