简体   繁体   中英

JAX-RS: map method entity based on method annotation

I am using JAX-RS 2.0 with Jersey 2.6. I was wondering if it was possible to have something like this:

@GET
@Path("/get/{id}")
@MapTo(type = MyObjectDTO.class)
public MyObject getMyObject(@PathParam("id") String id){
  MyObject o = ...
  return o;
}

In the method above I am returning an instance of MyObject . However, I have defined the MapTo annotation to indicate that I want to map this object to MyObjectDTO . The way I was thinking this could work is to process the response early in a ContainerResponseFilter , detect the annotation MapTo and, assuming no error occurred, replace the entity in the response with an instance of MyObjectDTO created appropriately from the existing entity (of type MyObject ).

However, I couldn't find a way to get the Method in the resource that was just called after the request came in, ie, the getMyObject method, so that I can scan for the MapTo annotation.

Is there a way to achieve this in a JAX-RS-y kind of way?

Is this some serious reason you cannot return dto object? Sounds very strange...You can probably use AOP but I guess it would be bad practive Here the Spring AOP example http://docs.spring.io/spring/docs/2.5.4/reference/aop.html

I think I found a solution by reading this SO . I created a class that looks like this:

@Provider // or register in the configuration...
public class DTOMapperFeature implements DynamicFeature {
  @Override
  public void configure(ResourceInfo resourceInfo, FeatureContext context) {
    for (Annotation annotation : resourceInfo.getResourceMethod().getAnnotations()) {
      if (annotation instanceof MapTo) {
        MapTo mapTo = (MapTo) annotation;
        // Note: additional validation (return type shouldn't be void, 
        // collections are out etc.) is required before creating this,
        // or should be pushed in the DTOMapperFilter.
        // You get the gist: this filter will map the entity to an instance
        // of the specified class (using a constructor in this case).
        context.register(new DTOMapperFilter(
          resourceInfo.getResourceMethod().getReturnType(), 
          mapTo.getResponseType());
      }
    }
  }
  @Priority(/* appropriate priority here! */)
  public final static class DTOMapperFilter implements ContainerResponseFilter {
    public DTOMapperFilter(Class<?> declaredReturnType, Class<?> responseType) { 
      // implementation omitted: find DTO constructor etc.
      // throw if responseType does NOT have a constructor that takes an instance
      // of declaredReturnType: catch errors at application bootstrap!
    }
    @Override
    public void filter(
      ContainerRequestContext requestContext, 
      ContainerResponseContext responseContext) throws IOException {
        // implementation omitted: create instance of DTO class using constructor
      }
  }
}

Given sensible exceptions will be thrown from either the constructor of DTOMapperFilter or the configure method above, this should be pretty robust and errors detectable at test time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM