2012-12-20 39 views
57

我使用RESTEasy JAX-RS實現部署了一個web服務組件到JBoss應用服務器7JAX-RS中需要@QueryParam(以及他們不在時需要做什麼)

是否有標註可用來聲明要求,強制@QueryParam在JAX-RS參數?而且,如果不是,那麼處理這些參數丟失的情況的「標準」方法是什麼?

我的網絡服務(資源)方法返回JSON字符串化的結果時正確調用所有必需的參數,但我不知道什麼是最好的方式向調用方指出缺少必需的參數。

+4

您可以添加一個'@ DefaultValue'註釋並在缺失時將該參數設置爲適當的值。如果你不能有一個默認值並且這個參數非常重要,那麼你應該檢查'null'的參數並返回一個'400 Bad request'狀態碼。 – toniedzwiedz

回答

62

好問題。不幸的是(或者幸運的是)JAX-RS沒有任何機制來強制實現任何參數。如果沒有提供參數,它的值將是NULL,您的資源應該相應地處理它。我會建議使用WebApplicationException通知用戶:

@GET 
@Path("/some-path") 
public String read(@QueryParam("name") String name) { 
    if (name == null) { 
    throw new WebApplicationException(
     Response.status(HttpURLConnection.HTTP_BAD_REQUEST) 
     .entity("name parameter is mandatory") 
     .build() 
    ); 
    } 
    // continue with a normal flow 
} 
+12

[JAX-RS 1.0的文檔](https://wikis.oracle.com/display/Jersey/Overview+of+JAX-RS+1.0+Features)表示它不總是爲空。它將是「List,Set或SortedSet的一個空集合,其他對象類型爲null,以及基元類型的Java定義默認值。 – hotshot309

+2

'String'不是原始類型,因此它對於其他對象類型爲「null」 – yegor256

+10

也建議不要使用HttpURLConnection.HTTP_BAD_REQUEST,而應該使用javax.ws.rs.core.Response.Status.BAD_REQUEST以保持與方法的一致預期的參數。 – cmonkey

45

您可以使用javax.validation註解來強制執行的參數是通過@javax.validation.constraints.NotNull註解它們強制性的。參見an example for Jerseyone for RESTeasy

所以,你的方法是簡單地變成:

@GET 
@Path("/some-path") 
public String read(@NotNull @QueryParam("name") String name) { 
    String something = 
    // implementation 
    return something; 
} 

注意異常被再由JAX-RS提供的一些錯誤代碼轉換。通常可以通過註冊您自己的實現javax.ws.rs.ext.ExceptionMapper<javax.validation.ValidationException>來覆蓋它。

這提供了一種集中的方式來將強制參數轉換爲錯誤響應,並且不需要代碼重複。

+11

此方法的一個問題是錯誤消息沒有指定缺少參數的名稱,例如「arg1不能爲null」。幸運的是,Bean Validation規範引入了接口javax.validation.ParameterNameProvider。對於JAX-RS,我們可以使用註釋QueryParam和PathParam來獲取名稱(因爲反射不允許獲取參數名稱)。一個例子可以在這裏找到:http://stackoverflow.com/q/22496527/998772 –

+0

是的,我經歷了這種痛苦,並問了一個[關於它的問題](http://stackoverflow.com/questions/22567097/jersey-豆驗證-parameternameprovider)。這是可行的,只需要更多的代碼來編寫。 –

+0

我試圖做類似的事情,但@NotNull沒有檢測到它,即使我從URL中省略了這個查詢參數。我已經在這裏開始了一個線程[鏈接](http://stackoverflow.com/questions/25737837/notnull-annotation-is-not-checking-null-queryparameter-in-jersey-rest-resource) – PST

14

我遇到了同樣的問題,並決定,我不想分散在我的REST代碼一個極大樣板null檢查,所以這這是我決定的事情:

  1. 創建導致的註解當沒有指定必需的參數時拋出異常。
  2. 處理拋出的異常的方式與我處理在我的REST代碼中拋出的所有其他異常的方式相同。

對於1),我實現了以下注釋:

import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Target(ElementType.PARAMETER) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface Required 
{ 
    // This is just a marker annotation, so nothing in here. 
} 

...及以下JAX-RS ContainerRequestFilter去執行:

import java.lang.reflect.Parameter; 
import javax.ws.rs.QueryParam; 
import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.container.ResourceInfo; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.ext.Provider; 

@Provider 
public class RequiredParameterFilter implements ContainerRequestFilter 
{ 
    @Context 
    private ResourceInfo resourceInfo; 

    @Override 
    public void filter(ContainerRequestContext requestContext) 
    { 
     // Loop through each parameter 
     for (Parameter parameter : resourceInfo.getResourceMethod().getParameters()) 
     { 
      // Check is this parameter is a query parameter 
      QueryParam queryAnnotation = parameter.getAnnotation(QueryParam.class); 

      // ... and whether it is a required one 
      if (queryAnnotation != null && parameter.isAnnotationPresent(Required.class)) 
      { 
       // ... and whether it was not specified 
       if (!requestContext.getUriInfo().getQueryParameters().containsKey(queryAnnotation.value())) 
       { 
        // We pass the query variable name to the constructor so that the exception can generate a meaningful error message 
        throw new YourCustomRuntimeException(queryAnnotation.value()); 
       } 
      } 
     } 
    } 
} 

您需要註冊ContainerRequestFilter與使用JAX-RS庫註冊其他@Provider類的方法相同。也許RESTEasy自動爲你做。

對於2),我處理使用通用的JAX-RS ExceptionMapper所有運行時異常:

import javax.ws.rs.core.Response; 
import javax.ws.rs.ext.ExceptionMapper; 
import javax.ws.rs.ext.Provider; 

@Provider 
public class MyExceptionMapper implements ExceptionMapper<RuntimeException> 
{ 
    @Override 
    public Response toResponse(RuntimeException ex) 
    { 
     // In this example, we just return the .toString() of the exception. 
     // You might want to wrap this in a JSON structure if this is a JSON API, for example. 
     return Response 
      .status(Response.Status.BAD_REQUEST) 
      .entity(ex.toString()) 
      .build(); 
    } 
} 

和以前一樣,記得你的JAX-RS庫註冊類。

+1

這是否提供了一些東西@ javax.validation.constraints.NotNull不會做? –

+1

@MichaelHaefele它保留參數名稱,這對於顯示有意義的錯誤消息很有用。如果使用'NotNull'註釋,則參數名稱會丟失,這是不幸的。這是讓我寫我自己的註釋的問題。但也見https://stackoverflow.com/questions/13968261/required-queryparam-in-jax-rs-and-what-to-do-in-their-absence/31893626?noredirect=1#comment35934905_21920512。自從我寫這段代碼以來,事情可能已經發生變化 – Zero3

相關問題