Ich stelle eine Webdienstkomponente mithilfe der RESTEasy JAX-RS- Implementierung für JBoss Application Server 7 bereit .
Gibt es eine Anmerkung, um erforderliche, obligatorische @QueryParam- Parameter in JAX-RS zu deklarieren ? Und wenn nicht, wie geht man dann standardmäßig mit Situationen um, in denen solche Parameter fehlen?
Meine Webdienst- (Ressourcen-) Methoden geben JSON-stringifizierte Ergebnisse zurück, wenn sie ordnungsgemäß mit allen obligatorischen Argumenten aufgerufen werden. Ich bin mir jedoch nicht sicher, wie ich dem Aufrufer am besten anzeigen kann, dass ein erforderlicher Parameter fehlt.
@DefaultValue
Anmerkung hinzufügen und den Parameter auf einen geeigneten Wert setzen, wenn er fehlt. Wenn Sie keinen Standardwert haben können und der Parameter wirklich wichtig ist, sollten Sie den Parameter möglicherweise überprüfennull
und einen400 Bad request
Statuscode zurückgeben.Antworten:
Gute Frage. Leider (oder vielleicht zum Glück) gibt es in JAX-RS keinen Mechanismus, um Parameter obligatorisch zu machen. Wenn ein Parameter nicht angegeben wird, ist sein Wert
NULL
und Ihre Ressource sollte entsprechend damit umgehen. Ich würde empfehlen,WebApplicationException
Ihre Benutzer zu informieren:@GET @Path("/some-path") public String read(@QueryParam("name") String name) { if (name == null) { throw new WebApplicationException( Response.status(Response.Status.BAD_REQUEST) .entity("name parameter is mandatory") .build() ); } // continue with a normal flow }
quelle
String
ist kein primitiver Typ, daher ist es "null für andere Objekttypen"BadRequestException
die ausgelöst werden kann und die mehr oder weniger das tut, was der obige Code tut, aber es Ihnen auch ermöglicht, diese Ausnahme programmgesteuert abzufangen.Sie können
javax.validation
Anmerkungen verwenden, um zu erzwingen, dass die Parameter obligatorisch sind, indem Sie sie mit Anmerkungen versehen@javax.validation.constraints.NotNull
. Sehen Sie sich ein Beispiel für Jersey und eines für RESTeasy an .Ihre Methode würde also einfach werden:
@GET @Path("/some-path") public String read(@NotNull @QueryParam("name") String name) { String something = // implementation return something; }
Beachten Sie, dass die Ausnahme dann vom JAX-RS-Anbieter in einen Fehlercode übersetzt wird. Es kann normalerweise überschrieben werden, indem Sie Ihre eigene Implementierung von registrieren
javax.ws.rs.ext.ExceptionMapper<javax.validation.ValidationException>
.Dies bietet eine zentralisierte Möglichkeit, obligatorische Parameter in Fehlerantworten zu übersetzen, und es ist keine Codeduplizierung erforderlich.
quelle
Ich stieß auf dasselbe Problem und entschied, dass ich keine millionenfachen Nullprüfungen auf meinem REST-Code haben wollte. Deshalb habe ich mich dazu entschlossen:
Für 1) habe ich die folgende Anmerkung implementiert:
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. }
... und das folgende JAX-RS
ContainerRequestFilter
, um es durchzusetzen: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()); } } } } }
Sie müssen
ContainerRequestFilter
das genauso registrieren, wie Sie Ihre anderen@Provider
Klassen bei Ihrer JAX-RS-Bibliothek registrieren würden . Vielleicht erledigt RESTEasy das automatisch für Sie.Für 2) behandle ich alle Laufzeitausnahmen mit einem generischen 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(); } }
Denken Sie nach wie vor daran, die Klasse bei Ihrer JAX-RS-Bibliothek zu registrieren.
quelle
NotNull
Anmerkung verwenden, was unglücklich ist. Das war das Problem, das mich dazu brachte, mir eine eigene Anmerkung zu schreiben. Siehe aber auch stackoverflow.com/questions/13968261/… . Die Dinge könnten sich geändert haben, seit ich diesen Code geschrieben habe.Der wahrscheinlich einfachste Weg ist,
@Nonnull
vonjavax.annotation
zu verwenden, um dies zu erreichen. Es ist super einfach zu bedienen, da Sie es nur vorher hinzufügen müssen,@QueryParam
wie unten gezeigt.Beachten Sie jedoch, dass dies einen
IllegalArgumentException
Fehler auslöst, wenn der Parameter null ist, sodass die Antwort, die Sie zurücksenden, für eine Ausnahme das ist, was Sie tun. Wenn Sie es nicht abfangen, wird es eine sein500 Server Error
, obwohl das richtige, was Sie zurückschicken würden, eine sein würde400 Bad Request
. Sie können es abfangenIllegalArgumentException
und verarbeiten, um eine ordnungsgemäße Antwort zurückzugeben.Beispiel:
import javax.annotation.Nonnull; ... @GET @Path("/your-path") public Response get(@Nonnull @QueryParam("paramName") String paramName) { ... }
Die an den Anrufer zurückgegebene Standardfehlermeldung sieht folgendermaßen aus:
quelle