JAX-RS 服务中用于日期解析的@JsonFormat 被忽略

@JsonFormat for date parsing in JAX-RS service is ignored

我正在尝试将日期传递给 JAX-RS 服务。检查其他问题,例如:Date format Mapping to JSON Jackson

答案和文档显示有一个 jackson annotation 应该允许日期格式。

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;
    }
}

调用 Rest-Service 后,我收到 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.fromString(ParamConverters.java:259)

好像注释被忽略了。调试解析方法,模式设置为 EEE, dd MMM yyyy HH:mm:ss zzzEEE MMM d HH:mm:ss yyyy.

我正在使用 Spring 4.2.1,Jersey 2.22,它绑定了 jackson 2.5.4。

如何使用正确的模式解析日期?

更新: 进一步思考 JSON 仅用于输出解析。但这可能是关于JAX-RS参数解析的。

Param 转换是通过 ParamConverters. If you follow the stacktrace, you will see the ParamConverters$DateProvider. The next call is the HttpDateFormat class 进行解析的。

如果您查看 class 的顶部,您会看到支持的日期格式。这些是标准的 HTTP 数据格式

/**
 * 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";

据我所知或所知,没有可用的配置可以添加到此列表中。唯一的其他选择是编写自己的转换器。例如

@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); 
            }
        };
    }
}

这是一个完整的测试用例,使用 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);
    }
}

这里是测试框架的依赖

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
    <scope>test</scope>
</dependency>

另请参阅:

  • Read another parameter within jersey's ParamConverter再举个例子
  • 一个使用测试框架和 Spring-Jersey 应用程序的例子。