我正在使用Jersey 2.4创建一个简单的REST接口来提供JSON对象。我的问题是我正在尝试使用fastxml Jackson注释来控制输出,这对我来说不起作用。我已将注释放入我的bean类中,但它们会被忽略。
当我显式创建一个ObjectMapper并使用它来对Java bean进行字符串化时,我得到了我想要的输出,它尊重Jackson注释。但是,我更希望我不必执行此步骤,以便我的资源类可以简单地返回bean,并且Jersey框架负责对其进行字符串化。
我尝试使用Custom ObjectMapper with Jersey 2.2 and Jackson 2.1的答案来解决此问题,但是,这似乎对我没有用。我看到ContextResolver已创建,但从未被调用过。
我还花了很多时间试图解决这个看似简单的问题。我已将其删除为一个非常简单的测试用例,如下所示。在解决这个问题上,我将不胜感激。
资源Java类:
@Path("resource")
public class MainResource {
public static class Foobar {
@JsonIgnore
private String foo = "foo";
private String baa = "baa";
private Map<String, List<? extends Number>> map = new HashMap<>();
public Foobar() {
map.put("even", Arrays.asList(new Integer[] { 2, 4, 6, 8, 10 }));
map.put("odd", Arrays.asList(new Integer[] { 1, 3, 5, 7, 9 }));
map.put("float", Arrays.asList(new Float[] { 1.1F, 2.2F, 3.3F }));
}
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBaa() {
return baa;
}
public void setBaa(String baa) {
this.baa = baa;
}
@JsonAnyGetter
public Map<String, List<? extends Number>> getMap() {
return map;
}
public void setMap(Map<String, List<? extends Number>> map) {
this.map = map;
}
}
private ObjectMapper om = new ObjectMapper();
@GET
@Path("get-object")
@Produces(MediaType.APPLICATION_JSON)
public Foobar getObject() {
// In this method, I simply return the bean object but the WRONG JSON syntax is generated.
return new Foobar();
}
@GET
@Path("get-string")
@Produces(MediaType.APPLICATION_JSON)
public String getString() throws JsonProcessingException {
// This method returns the RIGHT JSON syntax but I don't want to have to explicitly use the ObjectMapper.
Foobar foobar = new Foobar();
return om.writeValueAsString(foobar);
}
}
的web.xml:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<module-name>sample</module-name>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>ie.cit.nimbus.sample</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
POM依赖项:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
答案 0 :(得分:11)
编辑:不要使用旧方法,因为它会产生错误(至少与Android设备有关,有关详细信息,请参阅EDIT2)。在我的测试中,Jersey v2.6似乎解决了@Provide
的问题,这种方法不起作用。我能够使用这个简单的提供程序:
@Provider
public class JerseyMapperProvider implements ContextResolver<ObjectMapper> {
private static ObjectMapper apiMapper = ObjectMapperManager.createMapperForApi();
@Override
public ObjectMapper getContext(Class<?> type)
{
return apiMapper;
}
}
所以请不要使用下面的黑客。
OLD APPROACH
使用
@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper>
对我来说不起作用(Jersey 2.4&amp; Jackson 2.3),也许这是因为杰克逊提供商在代码中报告了ContextResolver
应该在JacksonJsonProvider.java
注册的错误(2.3 RC1):
@Override
protected ObjectMapper _locateMapperViaProvider(Class<?> type, MediaType mediaType)
{
if (_providers != null) {
ContextResolver<ObjectMapper> resolver = _providers.getContextResolver(ObjectMapper.class, mediaType);
/* Above should work as is, but due to this bug
* [https://jersey.dev.java.net/issues/show_bug.cgi?id=288]
* in Jersey, it doesn't. But this works until resolution of
* the issue:
*/
if (resolver == null) {
resolver = _providers.getContextResolver(ObjectMapper.class, null);
}
if (resolver != null) {
return resolver.getContext(type);
}
}
return null;
}
但至少我无法访问https://jersey.dev.java.net/issues/show_bug.cgi?id=288,所以我不知道这个bug是什么。
但是我找到了一个解决方法(如果你愿意,那就是黑客)。只需使用正确的注释扩展JacksonJsonProvider
,然后像这样返回ObjectMapper
:
@Provider
@Consumes(MediaType.APPLICATION_JSON) // NOTE: required to support "non-standard" JSON variants
@Produces(MediaType.APPLICATION_JSON)
public class JacksonHackProvider extends JacksonJsonProvider {
@Override
protected ObjectMapper _locateMapperViaProvider(Class<?> type, MediaType mediaType) {
return new MyCustomObjectMapper();
}
}
无需做任何会自行注册的事情(查看日志,它会在您第一次访问json休息服务时注册)。现在这对我有用,不优雅,但我放弃了。
编辑:谨慎使用 - 我遇到了一个可能与此黑客有关的错误:Android凌空无法向请求正文发送POST / PUT请求,总是从框架中获取400,我将调查并报告我的发现。 EDIT2:每当一个带有凌空和OKHTTP
客户端的Android应用程序尝试执行POST或PUT请求时,这个hack确实负责通用400,所以不要使用它 - 在我的测试球衣2.6似乎解决此问题,以便您可以使用@Provide
方法
答案 1 :(得分:7)
不幸的是,每个人都比实际需要的更难。泽西队以他们的智慧决定整合杰克逊1.9,所以他们的东西不会帮助你。
但对我来说这很容易。就这样做:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.3.0</version>
</dependency>
现在获得了这个:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.4.1</version>
</dependency>
然后在你的web.xml中改变这一行:
<param-value>ie.cit.nimbus.sample</param-value>
成为:
<param-value>ie.cit.nimbus.sample,com.fasterxml.jackson.jaxrs.json</param-value>
应该这样做。
答案 2 :(得分:5)
使用Jersey 2.13
,您可以强制@Provider
使用相同的ObjectMapper
只应创建一个ObjectMapper
:
package com.example.api.environment.configs;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
public JacksonConfig() {
objectMapper = new ObjectMapper()
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.registerModule(new JodaModule());
};
@Override
public ObjectMapper getContext(Class<?> type) {
return objectMapper;
}
}
我将@Autowire
中的ObjectMapper
用于动态生成json-schema
个文档。
答案 3 :(得分:1)
有很多方法可以将 jackson 与 Jax-rs Jersey实现集成。
如果您看一下Mkyong教程:http://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/ 看来你也应该传递“POJOMappingFeature” - &gt;在web.xml中的init params中为true。 我认为这适用于 Jersey 1.8
如果您查看官方的泽西文档,请: https://jersey.java.net/nonav/documentation/latest/user-guide.html#json.jackson 您似乎应该实现一个Jax-rs提供程序并将该提供程序添加到您的应用程序资源
@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper>
他们为您提供了如何执行此操作的示例 https://github.com/jersey/jersey/blob/2.4.1/examples/json-jackson/src/main/java/org/glassfish/jersey/examples/jackson/MyObjectMapperProvider.java
我用这种方式解决了我的问题,杰克逊提供商正确地扫描了杰克逊的注释。
关闭主题我建议你在bean中使用这个语法来初始化map:
import static java.util.Arrays.asList;
public static class Foobar {
@JsonIgnore
private String foo = "foo";
private String baa = "baa";
private Map<String, List<? extends Number>> map = new HashMap<>(){{
put("even", asList(2, 4, 6, 8, 10));
put("odd", asList(1, 3, 5, 7, 9));
put("float", asList(1.1F, 2.2F, 3.3F));
}};
public Foobar() {
}
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBaa() {
return baa;
}
public void setBaa(String baa) {
this.baa = baa;
}
@JsonAnyGetter
public Map<String, List<? extends Number>> getMap() {
return map;
}
public void setMap(Map<String, List<? extends Number>> map) {
this.map = map;
}
}
答案 4 :(得分:-1)
像这样添加每个模型类
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Event {
-----
--
}
它对我有用,但我使用过codehus jackson jars