I have a controller: (as per Spring WebMVC @ModelAttribute parameter-style)
@GetMapping("/time/{date}")
@ResponseStatus(OK)
public LocalDate getDate(
@ModelAttribute("date") LocalDate date
) {
return date;
}
LocalDateFormatter encodes LocalDate
s from strings "now", "today" and typical "yyyy-MM-dd"-formatted strings, and decodes dates back to strings
public class LocalDateFormatter implements Formatter<LocalDate> {}
I have tested this controller via Spring Test. The test PASSES.
I set up a conversion service and mocked an MVC with it:
var conversion = new DefaultFormattingConversionService();
conversion.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());
mockMvc = MockMvcBuilders
.standaloneSetup(TimeController.class)
.setConversionService(conversionRegistry)
.build();
Test is parameterized and looks like this:
@ParameterizedTest
@MethodSource("args")
void getDate(String rawDate, boolean shouldConvert) throws Exception {
var getTime = mockMvc.perform(get("/time/" + rawDate));
if (shouldConvert) {
// Date is successfully parsed and some JSON is returned
getTime.andExpect(content().contentType(APPLICATION_JSON_UTF8));
} else {
// Unsupported rawDate
getTime.andExpect(status().is(400));
}
}
Here are the parameters:
private static Stream<Arguments> args() {
// true if string should be parsed
return Stream.of(
Arguments.of("now", true),
Arguments.of("today", true),
Arguments.of("thisOneShouldNotWork", false),
Arguments.of("2014-11-27", true)
);
}
As I've said, test passes.
But when launched from browser, a 400 error is received on ANY request.
How I've tried integrating conversion into Spring MVC (none of this worked):
Overriding WebMvcConfigurer
's method:
public class ServletConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new LocalDateFormatter());
// ALSO TRIED
registry.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());
}
}
Registering a FormattingConversionService
@Bean
public FormattingConversionService conversionService() {
var service = new FormattingConversionService();
service.addFormatter(new LocalDateFormatter());
return service;
}
Can someone tell me what's wrong?
P.S. I'm aware that this is not the best way to work with dates, but since it says in Spring reference that this should work, I wanted to try it out.
Define this bean for spring boot:
@Bean
public Formatter<LocalDate> localDateFormatter() {
return new Formatter<LocalDate>() {
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
if ("now".equals(text))
return LocalDate.now();
return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ISO_DATE.format(object);
}
};
}
if you use Spring MVC define like this:
@Configuration
@ComponentScan
@EnableWebMvc
public class ServletConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<LocalDate>() {
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
if ("now".equals(text))
return LocalDate.now();
return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ISO_DATE.format(object);
}
});
}
}
Don't forget implement today
function as parameter.