2016-08-19 6 views
1

私は、@PUT@POSTメソッドを実装するJersey 1.19.1リソースを持っています。 @PUTメソッドは、入力/要求本体としてJSON文字列を使用し、@POSTメソッドはプレーンテキストを受け取ります。 JSONマッピングの場合、私はJackson 2.8を使用しています。Jersey:ハードコードPOST/PUT ObjectMapper、Content-Typeヘッダなし

リソースがこのように動作するように定義されているので、クライアントがContent-Type要求ヘッダーを指定する必要はありません。なぜなら、Jerseyは要求本体で使用するものを特定する必要があるからです。私が代わりに、「この@PUT入力のため、このObjectMapperを使用する」ジャージーを伝えることである、または「常にこの入力は、この方法でapplication/jsonContent-Typeを持つことになりますと仮定します。」何をしたいです

@Produces(MediaType.APPLICATION_JSON) 
@Path("/some/endpoint/{id}") 
public class MyResource { 

    @PUT 
    public JsonResult put(
     @PathParam("id") String id, 
     // this should always be deserialized by Jackson, regardless of the `Content-Type` request header. 
     JsonInput input 
    ) { 
     log.trace("PUT {}, {}, {}", id, input.foo, input.bar); 
     return new JsonResult("PUT result"); 
    } 

    @POST 
    public JsonResult post(
     @PathParam("id") String id, 
     // this should always be treated as plain text, regardless of the `Content-Type` request header. 
     String input 
    ) { 
     log.trace("POST {}, {}", id, input); 
     return new JsonResult("POST result"); 
    } 
} 

私はthis answerを見つけましたが、そこに解決策は、クライアントが正しいContent-Typeヘッダを追加するために必要な、またはそれ以外の場合は、手動でオブジェクトのマッピングを行うべきであるということのようだとして、それは、私が探しているものではないのです。

答えて

0

私は回避策を考え出しました。 Jerseyリソースメソッドで使用するObjectMapperを宣言する代わりに、ResourceFilterFactoryに対応するResourceFilterと注釈タイプを作成することにしました。リソースクラスまたはメソッドにこのタイプの注釈が付けられると、は、要求のContent-Typeを注釈のパラメータで宣言されているものに置き換えます。ここで

は私のコードです:

OverrideInputType注釈:

@Target({ElementType.TYPE, ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface OverrideInputType { 
    // What the Content-Type request header value should be replaced by 
    String value(); 

    // which Content-Type request header values should not be replaced 
    String[] except() default {}; 
} 

OverrideInputTypeResourceFilter

public class OverrideInputTypeResourceFilter implements ResourceFilter, ContainerRequestFilter { 
    private MediaType targetType; 
    private Set<MediaType> exemptTypes; 

    OverrideInputTypeResourceFilter(
     @Nonnull String targetType, 
     @Nonnull String[] exemptTypes 
    ) { 
     this.targetType = MediaType.valueOf(targetType); 
     this.exemptTypes = new HashSet<MediaType>(Lists.transform(
      Arrays.asList(exemptTypes), 
      exemptType -> MediaType.valueOf(exemptType) 
     )); 
    } 

    @Override 
    public ContainerRequest filter(ContainerRequest request) { 
     MediaType inputType = request.getMediaType(); 
     if (targetType.equals(inputType) || exemptTypes.contains(inputType)) { 
      // unmodified 
      return request; 
     } 

     MultivaluedMap<String, String> headers = request.getRequestHeaders(); 
     if (headers.containsKey(HttpHeaders.CONTENT_TYPE)) { 
      headers.putSingle(HttpHeaders.CONTENT_TYPE, targetType.toString()); 
      request.setHeaders((InBoundHeaders)headers); 
     } 
     return request; 
    } 

    @Override 
    public final ContainerRequestFilter getRequestFilter() { 
     return this; 
    } 

    @Override 
    public final ContainerResponseFilter getResponseFilter() { 
     // don't filter responses 
     return null; 
    } 
} 

OverrideInputTypeResourceFilterFactory

public class OverrideInputTypeResourceFilterFactory implements ResourceFilterFactory { 

    @Override 
    public List<ResourceFilter> create(AbstractMethod am) { 
     // documented to only be AbstractSubResourceLocator, AbstractResourceMethod, or AbstractSubResourceMethod 
     if (am instanceof AbstractSubResourceLocator) { 
      // not actually invoked per request, nothing to do 
      log.debug("Ignoring AbstractSubResourceLocator {}", am); 
      return null; 
     } else if (am instanceof AbstractResourceMethod) { 
      OverrideInputType annotation = am.getAnnotation(OverrideInputType.class); 
      if (annotation == null) { 
       annotation = am.getResource().getAnnotation(OverrideInputType.class); 
      } 
      if (annotation != null) { 
       return Lists.<ResourceFilter>newArrayList(
        new OverrideInputTypeResourceFilter(annotation.value(), annotation.except())); 
      } 
     } else { 
      log.warn("Got an unexpected instance of {}: {}", am.getClass().getName(), am); 
     } 
     return null; 
    } 

} 
@Produces(MediaType.APPLICATION_JSON) 
@Path(/objects/{id}") 
public class MyResource { 
    @PUT 
// @Consumes(MediaType.APPLICATION_JSON) 
    @OverrideInputType(MediaType.APPLICATION_JSON) 
    public StatusResult put(@PathParam("id") int id, JsonObject obj) { 
     log.trace("PUT {}", id); 
     // do something with obj 
     return new StatusResult(true); 
    } 

    @GET 
    public JsonObject get(@PathParam("id") int id) { 
     return new JsonObject(id); 
    } 
} 

はジャージー2では、あなたはポストマッチングContainerRequestFilters

でこれを行うことができます:210例 MyResourceその使用を実証
関連する問題