RESTEasy JAX-RS実装を使用して、WebサービスコンポーネントをJBoss Application Server 7にデプロイします。
JAX-RSの必須、必須の@ QueryParamパラメーターを宣言するために使用できる注釈はありますか?そして、そうでない場合、そのようなパラメーターが欠落している状況に対処するための「標準的な」方法は何ですか?
私のWebサービス(リソース)メソッドは、すべての必須引数で正しく呼び出されたときにJSON文字列化された結果を返しますが、必要なパラメーターが欠落していることを呼び出し元に示す最善の方法はわかりません。
良い質問。残念ながら(または幸いなことに)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
}
javax.validation
アノテーションを使用して、パラメーターに@javax.validation.constraints.NotNull
アノテーションを付けることで、パラメーターが必須であることを強制できます。 ジャージーの例 および RESeasyの例 を参照してください。
したがって、メソッドは次のようになります。
@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>
の独自の実装を登録することでオーバーライドできます。
これにより、必須パラメーターをエラー応答に変換する一元化された方法が提供され、コードの重複は不要です。
私は同じ問題にぶつかり、RESTコード全体に無数のボイラープレートnullチェックが散在することを望まないことを決定しました。
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
は、他の@Provider
クラスをJAX-RSライブラリに登録するのと同じ方法で登録する必要があります。たぶん、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ライブラリに登録することを忘れないでください。
おそらく最も簡単な方法は、@Nonnull
からjavax.annotation
を使用してこれを達成することです。以下に示すように、@QueryParam
の前に追加するだけなので、非常に簡単に使用できます。
ただし、パラメーターがnullの場合、これはIllegalArgumentException
をスローするため、返送する応答は例外に対して実行するものになります。インターセプトしない場合、送り返す正しいものは500 Server Error
になりますが、400 Bad Request
になります。 IllegalArgumentException
をインターセプトして処理し、適切な応答を返すことができます。
例:
import javax.annotation.Nonnull;
...
@GET
@Path("/your-path")
public Response get(@Nonnull @QueryParam("paramName") String paramName) {
...
}
呼び出し元に返されるデフォルトのエラーメッセージは次のようになります。
{"timestamp":1536152114437、 "status":500、 "error": "Internal Server Error"、 "exception": "Java.lang.IllegalArgumentException"、 "message": "comの@Nonnullパラメーター 'paramName'の引数/example/YourClass.getはnull "、" path ":"/path/to/your-path "}であってはなりません}