我已经编写了一个 rest 服务 API,它返回一种 map 布局的数据结构。映射条目可以来自字符串、整数或日期类型。其余服务方法支持 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?
有趣的是,当我使用请求 header “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>
野蝇 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 格式?
最佳答案
如果我们有要测试的模型类会有所帮助,这样我们就可以看到哪些提供者产生了哪些结果(在测试时)。但是没有它,我只会抛出一些事情来考虑
Glassfish 默认使用 MOXy用于 JSON/POJO 支持。我个人不喜欢使用 MOXy。起初我推广它的用法,因为它是 Jersey 推荐的,但过了一段时间,你开始了解它的局限性。 Glassfish 也附带 Jackson 支持,但我们需要显式禁用 MOXy,或者只注册 Jackson 功能(不可移植),或者结合禁用 MOXy 和 添加 Jackson 提供程序。
就 Wildfly 而言,如前所述需要考虑一件事 here in the Resteasy Documentation
21.6. Possible Conflict With JAXB Provider
If your Jackson classes are annotated with JAXB annotations and you have the
resteasy-jaxb-provider
[which Wildfly comes shipped with] in your classpath, you may trigger the Jettision JAXB marshalling code. To turn off the JAXB json marshaller use the@org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes("application/*+json")
on your classes.
另一件需要考虑的事情是,这两款服务器都附带了 Jackson 1.x 和 Jackson 2.x 的提供程序。使用哪个在编码结果上可能没有差异,但与此答案的下一部分相关(另请参阅 here - 尽管这提到了 JBoss AS7,但我不确定它是否适用于 Wildfly。我 < em>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;
}
}
Result
Glassfish: Jackson 2 not being used
Wildfly: Jackson 2 is used (even with JAXB annotations. Maybe you need to explicitly have the resteasy-jaxb-provider explicitly on the project classpath for the Jettison to kick in).
那么我们如何以可移植的方式修复 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 上进行测试
关于json - 为什么 Rest-Easy 和 Jersey 有不同的 JSON 输出格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28929460/