I'm trying to pass a date to a JAX-RS service. Checking other questions like: Date format Mapping to JSON Jackson
The answers and the documentation show that there is a jackson annotation which should allow date formatting.
public class SolutionFilter {
@MatrixParam("toDate")
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd", timezone="CET")
private Date toDate;
public void setToDate(Date toDate) {
this.toDate = toDate;
}
}
Upon calling the Rest-Service I'm getting a ParseException
:
Caused by: java.text.ParseException: Unparseable date: "2016-01-01"
at java.text.DateFormat.parse(DateFormat.java:366)
at org.glassfish.jersey.message.internal.HttpDateFormat.readDate(HttpDateFormat.java:137)
at org.glassfish.jersey.server.internal.inject.ParamConverters$DateProvider$1.fromString(ParamConverters.java:259)
It seems like the annotation is ignored. Debugging the parse method the pattern is set to EEE, dd MMM yyyy HH:mm:ss zzz
and EEE MMM d HH:mm:ss yyyy
.
I'm using Spring 4.2.1, Jersey 2.22 which binds jackson 2.5.4.
How can I get the dates parsed with the correct pattern?
Update: Thinking further about it the JSON is only used for output parsing. But this is probably about JAX-RS parameter parsing.
@JsonFormat is a Jackson annotation that we use to specify how to format fields and/or properties for JSON output. Specifically, this annotation allows us to specify how to format Date and Calendar values according to a SimpleDateFormat format.
How to deserialize Date from JSON using Jackson. In order to correct deserialize a Date field, you need to do two things: 1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method.
JSON does not have a built-in type for date/time values. The general consensus is to store the date/time value as a string in ISO 8601 format.
We can format a date using the setDateFormat() of ObjectMapper class. This method can be used for configuring the default DateFormat when serializing time values as Strings and deserializing from JSON Strings.
Param conversion is done with ParamConverter
s. If you follow the stacktrace, you will see the ParamConverters$DateProvider. The next call is the HttpDateFormat
class which does the parsing.
If you look at the top of the class, you will see the date formats supported. These are standard HTTP data formats
/**
* The date format pattern for RFC 1123.
*/
private static final String RFC1123_DATE_FORMAT_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz";
/**
* The date format pattern for RFC 1036.
*/
private static final String RFC1036_DATE_FORMAT_PATTERN = "EEEE, dd-MMM-yy HH:mm:ss zzz";
/**
* The date format pattern for ANSI C asctime().
*/
private static final String ANSI_C_ASCTIME_DATE_FORMAT_PATTERN = "EEE MMM d HH:mm:ss yyyy";
As far as I know or can tell, there is no configuration available where we can add to this list. The only other option is to write your own converter. For example
@Provider
public class DateParamConverterProvider implements ParamConverterProvider {
private final String format;
public DateParamConverterProvider(String dateFormat) {
this.format = dateFormat;
}
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType,
Type genericType,
Annotation[] annotations) {
if (rawType != Date.class) { return null; }
return (ParamConverter<T>) new ParamConverter<Date>() {
@Override
public Date fromString(String value) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
try {
return formatter.parse(value);
} catch (Exception ex) {
throw new WebApplicationException("Bad formatted date", 400);
}
}
@Override
public String toString(Date date) {
return new SimpleDateFormat(format).format(date);
}
};
}
}
Here is a complete test case using Jersey Test Framework
public class DateParamTest extends JerseyTest {
private static final String FORMAT = "MM-dd-yyyy";
@Path("date")
public static class DateResource {
@GET
public String get(@MatrixParam("since") Date date) {
return new SimpleDateFormat(FORMAT).format(date);
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(DateResource.class)
.register(new DateParamConverterProvider(FORMAT));
}
@Test
public void should_return_same_date_and_format() {
final String date = "09-30-2015";
Response response = target("date").matrixParam("since", date)
.request().get();
assertEquals(200, response.getStatus());
String returnDate = response.readEntity(String.class);
assertEquals(date, returnDate);
System.out.println(returnDate);
}
}
Here is the dependency for the test framework
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
See Also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With