JBT
JBT

Reputation: 8746

Modify response in ContainerResponseFilter

I want to have a common structure for JAX-RS resource responses. For example, suppose you have a PersonsResource, and a GET method like this:

@GET @Path("/{id}")
public Person get(@PathParam("id") String id) {
    return new Person(id); //
}

Suppose the response on the client side is a json like this: {"id":"some-id"}.

Now, what I want to achieve is to have a ContainerResponseFilter. It will modify the response so that it will wrap the original entity with a structure like this:

{  
   "meta":{  
      "href":"http://this.is.request/url"
   },
   "paging":{  
      "offset":0,
      "limit":10
   },
   "entity":{  
      "id":"some-id"
   }
}

I experimented my idea with code like below (where I used Lombok to reduce boilerplate code):

@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()));
    }
}

However, when I call the endpoint using curl, what I get is like this: {"entity":"Person(id=xyz)"}. Apparently, the corresponding MessageBodyWriter simply used the toString() method for the entity field in WrappedResponse. So, how can I make entity also serialized as json as defined by its JAXB annotations? Namely, for the example above, how can I make the response like {"entity":{"id":"xyz"}}?

BTW, I used the following dependencies:

'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'

I deployed my experiment code as a web app into Jetty on my Mac.

Upvotes: 3

Views: 2315

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209052

It should work if you switch out MOXy for Jackson

'org.glassfish.jersey.media:jersey-media-moxy:2.26'

'org.glassfish.jersey.media:jersey-media-json-jackson:2.26'

The reason is that MOXy (which uses JAXB) needs type information. Not sure the exact heuristics of how the type information is discovered, but from my experience, when it can't be found, it will just default to calling toString().

With Jackson on the other hand, it doesn't need the type information, as it will by default just introspect the bean properties to discover what should be serialized.

Upvotes: 1

Related Questions