刚开始使用泽西岛时,我一直试图在最新的泽西文档' building responses'中重现这个简单的例子。据我了解,此部分应说明如何使用Response
和ResponseBuilder
轻松返回与Entity<T>
结合使用的响应内容。
现在,文档指出默认支持多种数据类型(此处为:&#39; Representations and Java types&#39;)。其中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();
}
我在调用请求时总是得到相同的错误(下面的完整堆栈跟踪):
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.
我相信它说这个实体泛型类型找不到合适的提供商。但是,应该支持字符串OOTB?
我发现StringMessageProvider
可能是此提供程序的Jersey 1实现,而我在Jersey 2库中找到的最接近的相关类是jersey-common中org.glassfish.jersey.message.internal
中的类。在许多提供商中有StringMessageProvider
,在我看来,这似乎是一个潜在的预期提供商。
我已经查看了这个问题,虽然有很多人在错误地尝试使用自定义提供程序时遇到此问题,但我发现默认的OOTB提供程序无法正常工作..
我已经检查了我的libs,现在我的pom(以及其他)中有以下依赖项:
我已经在线查看了,但这似乎就是我所需要的,尽管我还没有确定在罐子里找到了适合String和JAXB / JSON的提供程序类。
POST HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1
Content-Length: 0
又尝试了几种变体。
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)
同样的错误(对于application / json)现在我已经用@XmlRootElement
注释了一个类,并尝试按泽西文档的方法返回它:
@GET
@Produces(MediaType.APPLICATION_JSON)
public Foo sampleFoo() {
Foo foo = new Foo();
return foo;
}
Foo
注释@XmlRootElement
。
我还添加了jersey-media-json-jackson作为依赖项,我可以看到它包含一个显式的JSONJaxb提供程序。但是,它似乎不会以某种方式被拾取。
答案 0 :(得分:23)
javax.ws.rs.client.Entity
是一个客户端类。 JAX-RS规范没有说明它在服务器端的用法。但我可以通过许多不同的测试确认,结果将与您所看到的相似(至少使用Jersey)。使用Resteasy,它只会发送Entity.toString()
由于这对Resteasy或Jersey都不起作用,我不会说这是一个错误,但可能是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();
}
以上也失败了。但你说
并没有错...默认支持多种数据类型
他们是。要让您的示例发挥作用,只需将Entity.text("someContent")
更改为"someContent"
return Response.created(createdUri).entity("someContent").build();
只是为了完整性,client side usage可能看起来像
Response response = webTarget.request().post(Entity.text("Hello World"));
效果很好。
直到(我相信)Jersey 2.9,jersey-media-json-jackson
模块未自动配置。因此,对于2.6,我们需要通过web.xml
或Application
子类中的包扫描来设置配置。无论哪种方式,都需要web.xml
。正如here所述,关于2.x servlet环境,Tomcat 6是。
在Servlet 2.5环境中,您必须在Web应用程序的web.xml部署描述符文件中显式声明Jersey容器Servlet。
因此,要扫描JSON提供程序类,应在jersey.config.server.provider.packages
init-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>
您还可以使用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>
注意:除了使用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>
另一方面,为了简化开发,我刚刚创建了一个带有以下坐标的简单Maven原型
GroupId: org.glassfish.jersey.archetypes
ArtifactId: jersey-quickstart-webapp
Version: 2.6
答案 1 :(得分:1)
就text / plain格式而言,这有用吗?
return Response.created(createdUri).type(MediaType.TEXT_PLAIN).entity("someContent").build();
对于JSON输出,我有这些依赖
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
以及jaxb实现。任何人都会这样做,我用
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
我还定义了一个对象映射器提供程序,但我并不是100%确定它是必需的(除非你想自定义):
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
ObjectMapper mapper;
public ObjectMapperProvider() {
mapper = new ObjectMapper();
mapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
mapper.configure( SerializationFeature.INDENT_OUTPUT, true );
mapper.configure( SerializationFeature.WRITE_NULL_MAP_VALUES, true );
mapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true );
mapper.setAnnotationIntrospector( new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()) );
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
另外,我认为您需要注册Jackson功能:
@ApplicationPath("")
public class Application extends ResourceConfig {
public Application() {
register( JacksonFeature.class );
}
}
我应该注意,这都是使用Jersey 2.11配置的。