为什么Rest-Easy和Jersey有不同的JSON输出格式?

时间:2015-03-08 17:17:41

标签: json glassfish jersey jax-rs resteasy

我编写了一个休息服务API,它以一种地图布局的形式返回数据结构。映射条目可以来自String,Integer或Date类型。其余服务方法支持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格式?

2 个答案:

答案 0 :(得分:4)

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

Glassfish默认使用MOXy来支持JSON / POJO。我个人不喜欢使用MOXy。起初我提升了它的用法,因为它是泽西岛推荐的,但过了一段时间,你开始了解它的局限性。 Glassfish还附带Jackson支持,但我们需要明确禁用MOXy,或者只注册Jackson功能(不可移植)或者添加杰克逊提供商的混合MOXy

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

  

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

     

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

另一件需要考虑的事情是两台服务器都附带了Jackson 1.x和Jackson 2.x的提供商。哪一个使用过的编组结果可能没有区别,但与本答案的下一部分有关(另见here - 虽然这提到了JBoss AS7,但我不确定它是否适用于Wildfly。我认为 Wildfly默认使用Jackson 2。

测试使用哪个提供程序的一种方法是创建ContextResolver。现在,下一个示例仅用于测试目的(您通常不会自己添加Jackson,但杰克逊提供商)。

将此依赖项添加到项目中

<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:杰克逊2未被使用
   Wildfly:使用了Jackson 2(即使使用JAXB注释。也许你需要明确地在项目类路径中明确地使用resteasy-jaxb-provider以便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。

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

答案 1 :(得分:3)

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

RESTeasy和Jersey都提供了类似application/jsonapplication/xml等媒体类型的序列化程序,以及未找到更好的序列化程序时使用的默认序列化程序。

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

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

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

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