在Jersey 2中使用默认的Providers/MessageBodyWriters

Mar*_*ans 9 rest jax-rs java-6 jersey-2.0 server

刚刚开始使用Jersey,我一直试图在最新的Jersey文档" 构建响应 "中重现这个简单的例子.据我所知,这部分应该说明如何Response以及如何ResponseBuilder使用它来轻松地将响应与Entity<T>响应内容一起返回.

现在,文档声明默认支持几种数据类型(此处:' Representations和Java types ').String其中最重要的是,匹配任何媒体类型.

在我尝试的所有变化中,以下是最简单的:

@POST
public Response post() {
    URI createdUri;
    try {
        createdUri = new URI("http://test.lan");
    } catch (final URISyntaxException e) {
        throw new WebApplicationException(e);
    }

    return Response.created(createdUri).entity(Entity.text("someContent")).build();
}
Run Code Online (Sandbox Code Playgroud)

在调用请求时,我总是得到相同的错误(下面的完整堆栈跟踪): org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=text/plain, type=class javax.ws.rs.client.Entity, genericType=class javax.ws.rs.client.Entity.

我相信它说的是找不到这个Entity泛型类型的合适提供者.但是,应该支持字符串OOTB?

我发现这StringMessageProvider可能是这个提供程序的Jersey 1实现,而我在Jersey 2库中找到的最接近的相关类org.glassfish.jersey.message.internal是jersey-common中的类.在众多提供商StringMessageProvider中,我认为这是一个潜在的预期提供商.

我已经查找了这个问题,虽然有很多人在错误地尝试使用自定义提供程序时得到了这个,但我发现默认的OOTB提供程序无法正常工作.

我已经检查了我的libs,现在我的pom(以及其他)中有以下依赖项:

  • 新泽西州容器servlet的核心
  • 球衣的客户端
  • 球衣常见
  • 球衣服务器

我已经在线查看,但这似乎是我所需要的,尽管我还没有确定在jar中找到了适合String和JAXB/JSON的提供程序类.

上下文

  • Maven项目
  • 与tomcat servlet-api 6.0.29
  • 所有提到的球衣库的2.6版本
  • Eclipse kepler
  • 使用tomcat6 maven插件运行嵌入式tomcat(到目前为止工作正常)

Fiddler请求用于测试

POST HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1
Content-Length: 0
Run Code Online (Sandbox Code Playgroud)

并再次尝试了几种变化.

完整的堆栈跟踪

06-Jan-2015 21:13:54 org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=text/plain, type=class javax.ws.rs.client.Entity, genericType=class javax.ws.rs.client.Entity.
06-Jan-2015 21:13:54 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet TestService threw exception
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=text/plain, type=class javax.ws.rs.client.Entity, genericType=class javax.ws.rs.client.Entity.
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
    at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:103)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:88)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1154)
    at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:571)
    at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:378)
    at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:368)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:262)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:319)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1028)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:662)
Run Code Online (Sandbox Code Playgroud)

编辑

同样的错误(对于application/json)现在我已经注释了一个类@XmlRootElement并尝试在Jersey文档的方法中返回它:

@GET
@Produces(MediaType.APPLICATION_JSON) 
public Foo sampleFoo() {
    Foo foo = new Foo();

    return foo;
}
Run Code Online (Sandbox Code Playgroud)

在哪里Foo注释@XmlRootElement.

我还添加了jersey-media-json-jackson作为依赖项,我可以看到它包含一个显式的JSONJaxb提供程序.但是,它似乎没有以某种方式被拾取.

Pau*_*tha 23

首要问题:

javax.ws.rs.client.Entity是一个客户端类.JAX-RS规范没有说明它在服务器端的用法.但我可以通过许多不同的测试确认,结果将与您所看到的相似(至少使用Jersey).有了Resteasy,它就会发出Entity.toString()

由于这对Resteasy或Jersey都不起作用,我不会说它是一个bug,但可能是Jersey文档中的一个错误,例如它的用法如下:

@POST
@Consumes("application/xml")
public Response post(String content) {
  URI createdUri = ...
  String createdContent = create(content);
  return Response.created(createdUri)
                         .entity(Entity.text(createdContent)).build();
}
Run Code Online (Sandbox Code Playgroud)

以上也失败了.但你说话没错

...默认支持多种数据类型

像他们那样.要让您的示例正常工作,只需将其更改Entity.text("someContent")为简单"someContent"

return Response.created(createdUri).entity("someContent").build();
Run Code Online (Sandbox Code Playgroud)

而且为了完整性,客户端使用可能看起来像

Response response = webTarget.request().post(Entity.text("Hello World"));
Run Code Online (Sandbox Code Playgroud)

哪个工作得很好.

第二期:

直到(我相信)Jersey 2.9,jersey-media-json-jackson模块没有自动配置.因此,对于2.6,我们需要通过子类中web.xmlApplication子类中的包扫描来设置配置.无论哪种方式,web.xml 都是必需的.正如这里所说的2.x servlet环境,Tomcat 6是.

在Servlet 2.5环境中,您必须在Web应用程序的web.xml部署描述符文件中显式声明Jersey容器Servlet.

因此,要扫描JSON提供程序类,应在jersey.config.server.provider.packagesinit-param中指定包.一个示例web.xml就是这样的

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
    <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>
                thepackage.of.your.resources,
                org.codehaus.jackson.jaxrs      <!-- Jackson providers -->
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>
Run Code Online (Sandbox Code Playgroud)

您也可以使用Application子类(从中ResourceConfig扩展).我们只需要在中指定它web.xml.示例配置可能是类似的

public class MyApplication extends ResourceConfig {  
    public MyApplication() {
        register(JacksonFeature.class);
        packages("thepackage.of.your.resources");
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
    <servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>
            org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>jersey2.tomcat6.MyApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>MyApplication</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>
Run Code Online (Sandbox Code Playgroud)

注意:除了使用Eclipse之外,所有这些都是针对相同的环境进行测试的.我正在使用Netbeans,尽管它不应该有任何区别.我还需要唯一的Maven依赖项

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.version}</version>
    </dependency>
</dependencies>

<jersey.version>2.6</jersey.version>
Run Code Online (Sandbox Code Playgroud)

另外,为了简化开发,我刚刚创建了一个带有以下坐标的简单Maven原型

GroupId:     org.glassfish.jersey.archetypes
ArtifactId:  jersey-quickstart-webapp
Version:     2.6
Run Code Online (Sandbox Code Playgroud)

您还可以看到从Maven Archetype创建新项目