【问题标题】:Why have Rest-Easy and Jersey different JSON Output Formats?为什么 Rest-Easy 和 Jersey 有不同的 JSON 输出格式?
【发布时间】:2015-05-09 20:50:54
【问题描述】:

我编写了一个休息服务 API,它以一种地图布局返回数据结构。映射条目可以来自字符串、整数或日期类型。 rest 服务方法支持 XML 和 Json 输出。

现在我认识到 GlassFish (Jersey) 中的 JSON 结果与 Wildfly (Reas-Easy) 中的不同

使用 application/json 在 GlassFish 上运行其余服务时,输出如下所示:

{"entity":{"item":{"name":"$modified","value":{"@type":"xs:dateTime","$":"2015-02-17T22:33:57.634+01:00"}}}}

WildFly (Rest-Easy) 上的相同结果如下所示:

{"entity":[{"item":[{"name":"$modified","value":[1425822673120]}]}]}

谁能解释这种行为?我希望 WildFly 的输出应该类似于 GlassFish?

有趣的是,当我使用请求标头“application/xml”调用相同的方法时,两个系统都返回相同的(预期的)格式。

GlassFish XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity><item><name>$modified</name>
<value xsi:type="xs:dateTime">2015-02-17T22:33:57.634+01:00</value></item></entity></collection>

Wildfly XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity><item><name>$modified</name>
<value xsi:type="xs:dateTime">2015-03-08T14:51:13.120+01:00</value></item></entity></collection>

有没有办法为 Rest-Easy 配置 JSON 格式?

【问题讨论】:

    标签: json glassfish jersey jax-rs resteasy


    【解决方案1】:

    如果我们有要测试的模型类会有所帮助,这样我们就可以看到哪些提供者产生了哪些结果(在测试时)。但是没有它,我只会抛出一些需要考虑的事情

    Glassfish 默认使用 MOXy 来支持 JSON/POJO。我个人不喜欢使用 MOXy。一开始我推广了它的用法,这是 Jersey 推荐的,但过了一段时间,你开始了解它的局限性。 Glassfish 还附带了对 Jackson 的支持,但我们需要明确禁用 MOXy,或者只注册一个 Jackson 功能(不可移植),或者结合禁用 MOXy 添加一个 Jackson 提供程序。

    就 Wildfly 而言,需要考虑的一件事是提到的 here in the Resteasy Documentation

    21.6。可能与 JAXB 提供程序发生冲突

    如果您的 Jackson 类使用 JAXB 注释进行注释,并且您的类路径中有 resteasy-jaxb-provider [Wildfly 附带的],您可能会触发 Jettision JAXB 编组代码。要关闭 JAXB json 编组器,请在您的类上使用 @org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes("application/*+json")

    要考虑的另一件事是,两台服务器都附带了 Jackson 1.x 和 Jackson 2.x 的提供程序。使用哪一个可能在编组结果上没有区别,但与此答案的下一部分相关(另请参阅here - 虽然这提到了 JBoss AS7,但我不确定它是否适用于 Wildfly。我 think Wildfly 默认使用 Jackson 2)。

    测试正在使用哪个提供程序的一种方法是创建一个ContextResolver。现在下一个示例仅用于测试目的(您通常不会只添加 Jackson 本身,而是添加 Jackson provider)。

    将此依赖项添加到您的项目中

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.4.0</version>
    </dependency>
    

    添加这个类

    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.ws.rs.ext.ContextResolver;
    import javax.ws.rs.ext.Provider;
    
    @Provider
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper>{
    
        static final Logger logger 
                     = Logger.getLogger(ObjectMapperContextResolver.class.getName());
        final ObjectMapper mapper = new ObjectMapper();
    
        @Override
        public ObjectMapper getContext(Class<?> type) {
            logger.log(Level.INFO, "<===== ***** Jackon 2 is used ***** =====>");
            return mapper;
        } 
    }
    

    结果

    Glassfish: 没有使用 Jackson 2
    Wildfly: 使用了 Jackson 2(即使带有 JAXB 注释。也许您需要明确拥有 resteasy-jaxb-在项目类路径上明确提供者供 Jettison 启动)。

    那么我们如何以便携的方式修复 Glassfish 部署?我能够测试并让 Jackson 2 在两台服务器上使用的一种方法是通过添加服务器配置属性来禁用 MOXy。这是可移植的,因为该属性只不过是一个字符串。它将被 Resteasy 忽略。

    @ApplicationPath("/rest")
    public class AppConfig extends Application {
    
        @Override
        public Map<String, Object> getProperties() {
            Map<String, Object> properties = new HashMap<>();
            properties.put("jersey.config.disableMoxyJson", true);
            return properties;
        }
    }
    

    我们还需要将 Jackson 提供程序添加到项目中

    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.4.0</version>
    </dependency>
    

    奇怪的是我们必须添加这个依赖,因为 Glassfish 已经附带了它,但是如果我不添加它,我会得到一个 MessageBodyWiter not found。

    此解决方案已在 Wildfly 8.1 和 Glassfish 4.0 上进行了测试

    【讨论】:

    【解决方案2】:

    JAX-RS 指定接口MessageBodyWriter 用于序列化您的实体,但这仅定义将Java 对象转换为OutputStream。结果的外观取决于您或 JAX-RS 运行时。

    RESTeasy 和 Jersey 都带有用于 MediaType 的序列化器,例如 application/jsonapplication/xml 以及一个默认序列化器,如果找不到更好的序列化器,则使用该序列化器。

    对于将 Java 对象序列化为 XML,JAXB 是标准的,因此结果不应有差异(太多)。对于 JSON,情况有所不同,没有明确的标准,但有很多序列化器,例如:

    他们都以不同的方式处理某些事情,可以以不同的方式配置并在他们的历史中改变行为。

    回答最后一个问题:如果您在 Wildfly 上使用 RESTeasy,则通常使用 Jackson,您可以configure a lot。这是an example

    请注意,Jackson 配置选项已不时重命名。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-15
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多