修改 ContainerResponseFilter 中的响应
Modify response in ContainerResponseFilter
我想要 JAX-RS 资源响应的通用结构。例如,假设您有一个 PersonsResource 和一个像这样的 GET 方法:
@GET @Path("/{id}")
public Person get(@PathParam("id") String id) {
return new Person(id); //
}
假设客户端的响应是这样的json:{"id":"some-id"}
。
现在,我想要实现的是拥有一个ContainerResponseFilter。它将修改响应,以便使用如下结构包装原始实体:
{
"meta":{
"href":"http://this.is.request/url"
},
"paging":{
"offset":0,
"limit":10
},
"entity":{
"id":"some-id"
}
}
我用如下代码试验了我的想法(我使用 Lombok 来减少样板代码):
@Data @NoArgsConstructor @AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD) @XmlType
public class Person {
private String id;
}
@XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement
@Data @NoArgsConstructor @AllArgsConstructor
public class WrappedResponse {
private Object entity;
}
@Provider @Slf4j
public class WrappedResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
responseContext.setEntity(new WrappedResponse(responseContext.getEntity()));
}
}
但是,当我使用 curl 调用端点时,我得到的是这样的:
{"entity":"Person(id=xyz)"}
。显然,对应的MessageBodyWriter只是对WrappedResponse中的entity
字段使用了toString()
方法。那么,如何使实体也按照其 JAXB 注释的定义序列化为 json?即,对于上面的示例,我怎样才能做出像 {"entity":{"id":"xyz"}}
?
这样的响应
顺便说一句,我使用了以下依赖项:
'javax.servlet:javax.servlet-api:3.1.0'
'org.slf4j:slf4j-api:1.7.25'
'org.projectlombok:lombok:1.16.18'
'javax.ws.rs:javax.ws.rs-api:2.1'
'javax.xml.bind:jaxb-api:2.3.0'
'org.eclipse.persistence:org.eclipse.persistence.moxy:2.7.0'
'org.glassfish.jersey.containers:jersey-container-servlet:2.26'
'org.glassfish.jersey.ext:jersey-spring4:2.26'
'org.glassfish.jersey.core:jersey-server:2.26'
'org.glassfish.jersey.media:jersey-media-moxy:2.26'
我将实验代码作为 Web 应用程序部署到 Mac 上的 Jetty 中。
如果你为 Jackson 关闭 MOXy,它应该可以工作
'org.glassfish.jersey.media:jersey-media-moxy:2.26'
'org.glassfish.jersey.media:jersey-media-json-jackson:2.26'
原因是 MOXy(使用 JAXB)需要类型信息。不确定如何发现类型信息的确切启发式方法,但根据我的经验,当无法找到它时,它将默认调用 toString()
.
另一方面,对于 Jackson,它不需要类型信息,因为默认情况下它只会自省 bean properties 以发现应该序列化的内容。
我想要 JAX-RS 资源响应的通用结构。例如,假设您有一个 PersonsResource 和一个像这样的 GET 方法:
@GET @Path("/{id}")
public Person get(@PathParam("id") String id) {
return new Person(id); //
}
假设客户端的响应是这样的json:{"id":"some-id"}
。
现在,我想要实现的是拥有一个ContainerResponseFilter。它将修改响应,以便使用如下结构包装原始实体:
{
"meta":{
"href":"http://this.is.request/url"
},
"paging":{
"offset":0,
"limit":10
},
"entity":{
"id":"some-id"
}
}
我用如下代码试验了我的想法(我使用 Lombok 来减少样板代码):
@Data @NoArgsConstructor @AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD) @XmlType
public class Person {
private String id;
}
@XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement
@Data @NoArgsConstructor @AllArgsConstructor
public class WrappedResponse {
private Object entity;
}
@Provider @Slf4j
public class WrappedResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
responseContext.setEntity(new WrappedResponse(responseContext.getEntity()));
}
}
但是,当我使用 curl 调用端点时,我得到的是这样的:
{"entity":"Person(id=xyz)"}
。显然,对应的MessageBodyWriter只是对WrappedResponse中的entity
字段使用了toString()
方法。那么,如何使实体也按照其 JAXB 注释的定义序列化为 json?即,对于上面的示例,我怎样才能做出像 {"entity":{"id":"xyz"}}
?
顺便说一句,我使用了以下依赖项:
'javax.servlet:javax.servlet-api:3.1.0'
'org.slf4j:slf4j-api:1.7.25'
'org.projectlombok:lombok:1.16.18'
'javax.ws.rs:javax.ws.rs-api:2.1'
'javax.xml.bind:jaxb-api:2.3.0'
'org.eclipse.persistence:org.eclipse.persistence.moxy:2.7.0'
'org.glassfish.jersey.containers:jersey-container-servlet:2.26'
'org.glassfish.jersey.ext:jersey-spring4:2.26'
'org.glassfish.jersey.core:jersey-server:2.26'
'org.glassfish.jersey.media:jersey-media-moxy:2.26'
我将实验代码作为 Web 应用程序部署到 Mac 上的 Jetty 中。
如果你为 Jackson 关闭 MOXy,它应该可以工作
'org.glassfish.jersey.media:jersey-media-moxy:2.26''org.glassfish.jersey.media:jersey-media-json-jackson:2.26'
原因是 MOXy(使用 JAXB)需要类型信息。不确定如何发现类型信息的确切启发式方法,但根据我的经验,当无法找到它时,它将默认调用 toString()
.
另一方面,对于 Jackson,它不需要类型信息,因为默认情况下它只会自省 bean properties 以发现应该序列化的内容。