【问题标题】:Formatting LocalDateTime for JAX-RS为 JAX-RS 格式化 LocalDateTime
【发布时间】:2018-05-17 14:12:37
【问题描述】:

我正在结合使用 resteasy-jaxrs 和 jackson-datatype-jsr310 在响应中序列化 LocalDateTime。这适用于我的类中的属性,因为我可以添加必要的注释,例如

@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
public LocalDateTime getExpirationDate() {
    return expirationDate;
}

使用 LocalDateTimeAdapter

public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {
    @Override
    public LocalDateTime unmarshal(String s) throws Exception {
        return LocalDateTime.parse(s);
    }

    @Override
    public String marshal(LocalDateTime dateTime) throws Exception {
        return dateTime.toString();
    }
}

在 json 中我得到类似的东西

"expirationDate": "2026-07-17T23:59:59"

但是我有一个对象映射,这个映射也可以有 LocalDateTime 类型的项目,对于那些没有注释的项目,所以我在 json 响应中得到完整的对象,比如

"effectiveDate":       {
  "dayOfMonth": 1,
  "dayOfWeek": "FRIDAY",
  "month": "JUNE",
  "year": 2018, ...

有没有办法格式化每个 LocalDateTime 字段,无论它来自哪里?

保罗回答后更新

因为我已经有了 com.fasterxml.jackson.datatype:jackson-datatype-jsr310 依赖项,所以我添加了 ObjectMapperContextResolver 类并从我的 LocalDateTime 属性中删除了注释。可悲的是,所有 LocalDateTimes 现在都再次序列化为完整对象。在帖子的 cmets 中,我看到有人向 web.xml 添加了一个上下文参数,以便拾取 ObjectMapperContextResolver。将此添加到我的 web.xml 后,它看起来像这样。

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <display-name>Servlet 3.1 Web Application</display-name>
    <listener>
        <listener-class>com.kopi.web.InitListener</listener-class>
    </listener>
    <context-param>
        <param-name>resteasy.resources</param-name>
        <param-value>com.kopi.utils.ObjectMapperContextResolver</param-value>
    </context-param>
</web-app>

现在自从添加了 context-param resteasy.resources,webapp 不再启动了,因为

SEVERE: Servlet [com.kopi.rest.RestApplication] in web application [/kopi] threw load() exception
java.lang.RuntimeException: RESTEASY003130: Class is not a root resource.  It, or one of its interfaces must be annotated with @Path: com.kopi.utils.ObjectMapperContextResolver implements:  javax.ws.rs.ext.ContextResolver
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:179)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:158)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addPerRequestResource(ResourceMethodRegistry.java:77)
    at org.jboss.resteasy.spi.ResteasyDeployment.registration(ResteasyDeployment.java:482)
    at org.jboss.resteasy.spi.ResteasyDeployment.startInternal(ResteasyDeployment.java:279)
    at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:86)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.init(ServletContainerDispatcher.java:119)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.init(HttpServletDispatcher.java:36)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1194)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1110)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1000)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4902)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5212)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:724)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:700)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:596)
    at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1805)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

在其他 cmets 中,我看到版本可能是一个问题。所以我目前正在使用

org.jboss.resteasy:resteasy-jaxrs 3.5.1.Final
org.jboss.resteasy:resteasy-jackson-provider 3.5.1.Final
org.jboss.resteasy:resteasy-servlet-initializer 3.5.1.Final
com.fasterxml.jackson.datatype:jackson-datatype-jsr310 2.9.5

谢谢你,科比

【问题讨论】:

    标签: jax-rs resteasy localdate


    【解决方案1】:

    您可以使用 Jackson 使用 ContextResolver 全局配置它,而不是需要在单个属性上声明的 XmlAdapter。您可以在此处配置ObjectMapper 并使用映射器注册JavaTimeModule。此配置将是全局的,因此您不需要使用XmlAdapter。要了解如何配置它,您可以查看this post

    【讨论】:

    • 您好,保罗,感谢您的提示。不幸的是,现在我面临一个不同的问题。请你看看我的更新。谢谢。
    • 您在resteasy.resources 下列出了它。它不是资源。如果您使用@Provider 进行注释,则启用类路径扫描就足够了。否则,您需要以编程方式手动注册它。见stackoverflow.com/a/50357807/2587435
    • 您也可以使用resteasy.providers。那应该可以。
    • 您好 Paul,很抱歉我的回复迟了,但直到现在我才能测试您的输入。为了确保没有其他干扰,我创建了一个全新的项目,并仅使用您在其他帖子中的类 LocalDateResource、Person 和 ObjectMapperContextResolver。使用 ApplicationPath 注解添加必要的 javax.ws.rs.core.Application 类后,在 applicationstart 期间调用 ObjectMapperContextResolver 类的构造函数,我可以调用人员端点。但是结果还是一样的 :( getMapper() 是否应该在某个时候被调用?
    • 请求过程中是否调用了getContext()方法?
    【解决方案2】:

    @XmlJavaTypeAdapter 可以应用于整个包 (see doc)。

    当@XmlJavaTypeAdapter 注解在包级别定义时 适用于包内的所有引用 @XmlJavaTypeAdapter.type()。

    尝试将文件package-info.java 添加到具有地图的类旁边。假设类的包是com.acme.beans,适配器的包是com.acme.adapters,文件的内容应该是这样的:

    @XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
    package com.acme.beans;
    
    import com.acme.adapters.LocalDateTimeAdapter;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      • 2015-01-04
      • 2011-04-22
      相关资源
      最近更新 更多