使用Jackson ObjectMapper和Jersey

jcs*_*ale 14 java rest spring json jersey-2.0

我正在使用Jersey 2.4创建一个简单的REST接口来提供JSON对象.我的问题是我正在尝试使用fastxml Jackson注释来控制输出,这对我不起作用.我已将注释放入我的bean类中,但它们被忽略了.

当我显式创建一个ObjectMapper并使用它来对Java bean进行字符串化时,我得到了我想要的输出,它尊重了Jackson注释.但是,我更希望我不必执行此步骤,以便我的资源类可以简单地返回bean,并且Jersey框架负责对其进行字符串化.

我试图使用Custom ObjectMapper与Jersey 2.2和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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

pat*_*ckf 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以请不要使用我下面的黑客.


老方法

运用

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper>
Run Code Online (Sandbox Code Playgroud)

我没有为我工作(泽西岛2.4和杰克逊2.3),也许这是由于杰克逊提供商报告的代码中的错误ContextResolver应该在JacksonJsonProvider.java(2.3rc1)中注册:

 @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;
}
Run Code Online (Sandbox Code Playgroud)

但至少我无法访问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();
    }
}
Run Code Online (Sandbox Code Playgroud)

无需做任何事情,它会自己注册(检查日志,它将在您第一次访问json休息服务时注册).现在这对我有用,不优雅,但我放弃了.

编辑:请谨慎使用 - 我遇到一个可能与此黑客有关的错误:Android凌空无法向请求正文发送POST/PUT请求,总是从框架中获得400,我将调查并报告我的发现.

编辑2:这个黑客确实负责通用400每当一个Android应用程序与凌空和OKHTTP客户端试图尝试做POST或PUT请求所以不要使用这个 - 在我的测试球衣2.6似乎解决这个,所以你可以使用@Provide方法


rob*_*lco 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>
Run Code Online (Sandbox Code Playgroud)

现在获得这个:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.4.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

然后在你的web.xml中改变这一行:

<param-value>ie.cit.nimbus.sample</param-value>
Run Code Online (Sandbox Code Playgroud)

成为:

<param-value>ie.cit.nimbus.sample,com.fasterxml.jackson.jaxrs.json</param-value>
Run Code Online (Sandbox Code Playgroud)

应该这样做.

  • 如果您不喜欢包扫描或想要自定义ObjectMapper,您可以在`ResourceConfig`中注册(JacksonJsonProvider.class)`或`register(new JacksonJsonProvider(myObjectMapper))`. (2认同)

Nth*_*alk 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我用这个来@AutowireObjectMapper生成json-schema的飞行文件.


the*_*rmz 1

有很多方法可以将jacksonJax-rs Jersey 实现集成。

如果您查看 Mkyong 教程:http://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/ 看来您还应该传递“POJOMappingFeature”-> true web.xml 中的初始化参数。我认为这适用于Jersey 1.8

如果您查看官方 Jersey 文档: https://jersey.java.net/nonav/documentation/latest/user-guide.html#json.jackson 看来您应该实现一个 Jax-rs 提供程序并添加您的应用程序资源的提供者

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper>
Run Code Online (Sandbox Code Playgroud)

他们为您提供了如何执行此操作的示例 https://github.com/jersey/jersey/blob/2.4.1/examples/json-jackson/src/main/java/org/glassfish/jersey/examples/jackson/ MyObjectMapperProvider.java

我使用这种方式解决了我的问题,并且 Jackson 注释由 Jackson 提供者正确扫描。


题外话,我建议您在 bean 中使用以下语法来初始化映射:

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)