如何使用 Jersey JSON POJO 支持?

Posted

技术标签:

【中文标题】如何使用 Jersey JSON POJO 支持?【英文标题】:How do I use the Jersey JSON POJO support? 【发布时间】:2011-07-06 21:31:24 【问题描述】:

我有一个对象,我想在 JSON 中作为 RESTful 资源提供服务。我像这样打开了 Jersey 的 JSON POJO 支持(在 web.xml 中):

<servlet>  
    <servlet-name>Jersey Web Application</servlet-name>  
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>  
</servlet>  

但是当我尝试访问资源时,我得到了这个异常:

SEVERE: A message body writer for Java type, class com.example.MyDto, and MIME media type, application/json, was not found
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException
...

我要服务的类并不复杂,它所拥有的只是一些公共的 final 字段和一个设置所有这些字段的构造函数。这些字段都是字符串、原语、与此类似的类或其列表(我尝试使用普通列表而不是通用 Lists,但无济于事)。有谁知道给了什么?谢谢!

Java EE 6

球衣 1.1.5

玻璃鱼 3.0.1

【问题讨论】:

【参考方案1】:

为什么要使用 final 字段? 我正在使用球衣,我有一些 JAXB 对象/pojos,我所要做的只是用 @Produces("application/json") 注释我的资源方法,它开箱即用。我不必弄乱 web.xml。只需确保您的 pojo 注释正确。

这是一个简单的pojo

package test;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class SampleJaxbObject 

    private String field1;

    private Integer field2;

    private String field3;

    public String getField1() 
        return field1;
    

    public void setField1(String field1) 
        this.field1 = field1;
    

    public Integer getField2() 
        return field2;
    

    public void setField2(Integer field2) 
        this.field2 = field2;
    

    public String getField3() 
        return field3;
    

    public void setField3(String field3) 
        this.field3 = field3;
    



【讨论】:

谢谢!我已经能够让它与 JAXB 一起工作,但我专门寻找 Jersey POJO 写作,而不是 JAXB 写作。有最终字段会干扰吗?我有 final 字段,因为它们代表对象的不可变属性。【参考方案2】:

Jersey-json 有一个 JAXB 实现。您收到该异常的原因是您没有注册Provider,或者更具体地说,没有注册MessageBodyWriter。你需要在你的提供者中注册一个合适的上下文:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> 
    private final static String ENTITY_PACKAGE = "package.goes.here";
    private final static JAXBContext context;
    static 
        try 
            context = new JAXBContextAdapter(new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(false).build(), ENTITY_PACKAGE));
         catch (final JAXBException ex) 
            throw new IllegalStateException("Could not resolve JAXBContext.", ex);
        
    

    public JAXBContext getContext(final Class<?> type) 
        try 
            if (type.getPackage().getName().contains(ENTITY_PACKAGE)) 
                return context;
            
         catch (final Exception ex) 
            // trap, just return null
        
        return null;
    

    public static final class JAXBContextAdapter extends JAXBContext 
        private final JAXBContext context;

        public JAXBContextAdapter(final JAXBContext context) 
            this.context = context;
        

        @Override
        public Marshaller createMarshaller() 
            Marshaller marshaller = null;
            try 
                marshaller = context.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
             catch (final PropertyException pe) 
                return marshaller;
             catch (final JAXBException jbe) 
                return null;
            
            return marshaller;
        

        @Override
        public Unmarshaller createUnmarshaller() throws JAXBException 
            final Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setEventHandler(new DefaultValidationEventHandler());
            return unmarshaller;
        

        @Override
        public Validator createValidator() throws JAXBException 
            return context.createValidator();
        
    

这会在提供的包名称中查找 @XmlRegistry,这是一个包含 @XmlRootElement 注释 POJO 的包。

@XmlRootElement
public class Person 

    private String firstName;

    //getters and setters, etc.

然后在同一个包中创建一个ObjectFactory:

@XmlRegistry
public class ObjectFactory 
   public Person createNewPerson() 
      return new Person();
   

注册 @Provider 后,Jersey 应该有助于在您的资源中进行编组:

@GET
@Consumes(MediaType.APPLICATION_JSON)
public Response doWork(Person person) 
   // do work
   return Response.ok().build();

【讨论】:

谢谢!看起来我误解了 Jersey JSON/POJO 的工作原理。 仅供记录 - 此答案不再适用于泽西岛 v1.18。您不需要编写自己的 MessageBodyWriter 并且您的 @GET 方法的返回类型可以是 POJO 对象。 仅供参考,如果使用 maven,这将为您提供:&lt;dependency&gt; &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt; &lt;artifactId&gt;jersey-json&lt;/artifactId&gt; &lt;version&gt;1.8&lt;/version&gt; &lt;/dependency&gt; 第二个@Nilzor - 很好的问题,但这不再是最佳答案。 是的,强调一下,如果您今天遇到此问题,您的问题很可能是类路径问题,正如此处其他答案所述。【参考方案3】:

我遵循了here 的说明,其中显示了如何使用 Jersey 和 Jackson POJO(而不是 JAXB)。它也适用于 Jersey 1.12。

【讨论】:

嘿 smiths,虽然它的回答很关心 1.12 版。在 jersey-json v1.12 中没有 POJOMappingFeature 类。我们是否需要添加任何额外的 jar 或需要更改 Jersey 最新版本的配置。在官方球衣网站 (jersey.java.net/nonav/documentation/latest/json.html) 上,文档似乎很旧。请指导我,因为我不想将不必要的 JAXB 注释 @XMLRootElement 添加到我的 POJO 中。谢谢。 这是我的解决方案。【参考方案4】:

我是新手,但在将 jackson-all-1.9.0.jar 添加到类路径后,我能够使用 POJO。

【讨论】:

【参考方案5】:

如果您想使用 JAXB 注释,可以使用 @XmlRootElement(请参阅其他答案)。

但是,如果您更喜欢纯 POJO 映射,则必须执行以下操作(遗憾的是它没有写在文档中):

    将 jackson*.jar 添加到您的类路径(如@Vitali Bichov 所述); 在 web.xml 中,如果您使用 com.sun.jersey.config.property.packages 初始化参数,请将 org.codehaus.jackson.jaxrs 添加到列表中。这将在 Jersey 的扫描列表中包括 JSON 提供程序。

【讨论】:

很好...我完全忘记将@XmlRootElement 添加到我项目中的一个类中。谢谢! 天哪,谢谢。神奇的额外扫描包为我修复了它。我已经关注了所有其他有关类路径和手动提供程序注册的相关帖子。再次感谢。【参考方案6】:

您可能已经想通了,但您需要做的就是将这些 jackson jar 添加到您的类路径中:jackson-core、jackson-jaxrs、jackson-mapper 和 jackson-xc

正如其他人所指出的,似乎还有另一种方法。将此添加到您的“com.sun.jersey.config.property.packages”参数(如果使用 tomcat 和 web.xml):“org.codehaus.jackson.jaxrs”,如下所示:

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>org.codehaus.jackson.jaxrs</param- value>
</init-param>

这样做还需要在您的类路径中使用相同的 jackson jar

【讨论】:

【参考方案7】:

Jersey 2.0 使用 MOXy 和 Jackson 提供对 JSON 的支持。

如果 JAR 存在于类路径中,则默认启用 MOXy 支持,并且可以使用功能启用 Jackson 支持。这在 Jersey 2.0 用户指南 JSON 绑定一章中有详细解释:

https://jersey.java.net/documentation/latest/media.html#json

要在不需要配置的情况下添加 MOXy 支持,请将以下依赖项添加到您的 maven pom.xml

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.6</version>
</dependency>

【讨论】:

【参考方案8】:

这是为我做的 - Jersey 2.3.1

在 web.xml 文件中:

<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><my webapp packages>;org.codehaus.jackson.jaxrs</param-value>
</init-param>
</servlet>

在 pom.xml 文件中:

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.3.1</version>
</dependency>

【讨论】:

这对我有用,只有一个更正参数名称必须是 com.sun.jersey.config.property.packages 我从Maven 添加了jersey-media-json-jackson。有用。非常感谢。 @Pavlonator,如果您使用的是 JAXRS-2.0,param-namejersey.config.server.provider.packages,如果您仍在使用 1.x,param-name 是 com.sun.jersey.config。 property.packages【参考方案9】:

以下内容对我有用。我正在使用 Jersey 2.7 with Jackson 和在 Tomcat6 上运行的 Apache Felix (OSGi)。

public class MyApplication extends ResourceConfig 

    public MyApplication() 
        super(JacksonFeature.class);
        // point to packages containing your resources
        packages(getClass().getPackage().getName());
    

然后,在您的web.xml(或者在我的情况下,只是一个Hashtable)中,您可以像这样指定您的javax.ws.rs.Application

<init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value><MyApplication.class.getName()></param-value>
</init-param>

无需指定com.sun.jersey.config.property.pacakgescom.sun.jersey.api.json.POJOMappingFeature

只要确定你对

的依赖
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.7</version>
</dependency>

【讨论】:

【参考方案10】:

jersey-json 依赖项移到 pom.xml 的顶部为我解决了这个问题。

<dependencies>
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.18.1</version>
  </dependency>

  <!-- other dependencies -->

</dependencies>

【讨论】:

【参考方案11】:

这在 Jersey 2.30 中有效:

pom.xml:

<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-json-jackson</artifactId>
  <version>2.30</version>
</dependency>

WEB-INF/web.xml:

<servlet>
  <servlet-name>My Jersey REST Service</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <load-on-startup>1</load-on-startup>
  <!-- ATTENTION: Use Jackson for JSON: -->
  <init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.jackson.JacksonFeature</param-value>
  </init-param>
  <!-- ... -->
  <init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>com.example.myapp</param-value>
  </init-param>
</servlet>

【讨论】:

以上是关于如何使用 Jersey JSON POJO 支持?的主要内容,如果未能解决你的问题,请参考以下文章

笔记:Jersey REST 传输格式-JSON

Jersey 2.x 使用 Pojo 作为 POST 的参数

Java Atmosphere Jersey 从可广播返回 JSON 对象

将 Jersey/Jackson 配置为不使用 @XmlElement 字段注释进行 JSON 字段命名

在 Jackson/Jersey JAVA 上发布带有多个参数 JSON 和 String 的请求

如何使用JAX-RS和Jersey在Adobe AEM 6.2中发布json数据