Bohnenvalidierung in Jersey

1. Übersicht

In diesem Tutorial werfen wir einen Blick auf die Bean-Validierung mit dem Open-Source-Framework Jersey.

Wie wir bereits in früheren Artikeln gesehen haben, ist Jersey ein Open-Source-Framework für die Entwicklung von RESTful Web Services. Weitere Informationen zu Jersey finden Sie in unserer Einführung zum Erstellen einer API mit Jersey und Spring.

2. Bohnenvalidierung in Jersey

Bei der Validierung wird überprüft, ob einige Daten einer oder mehreren vordefinierten Einschränkungen entsprechen . Dies ist natürlich in den meisten Anwendungen ein sehr häufiger Anwendungsfall.

Das Java Bean Validation Framework (JSR-380) ist zum De-facto-Standard für die Verarbeitung dieser Art von Operationen in Java geworden. Weitere Informationen zu den Grundlagen der Java Bean-Validierung finden Sie in unserem vorherigen Tutorial.

Jersey enthält ein Erweiterungsmodul zur Unterstützung der Bean-Validierung . Um diese Funktion in unserer Anwendung nutzen zu können, müssen wir sie zunächst konfigurieren. Im nächsten Abschnitt erfahren Sie, wie Sie unsere Anwendung konfigurieren.

3. Anwendungs-Setup

Lassen Sie uns nun auf dem einfachen Fruit API-Beispiel aus dem hervorragenden Artikel zum Jersey MVC Support aufbauen.

3.1. Maven-Abhängigkeiten

Fügen wir zunächst die Bean Validation-Abhängigkeit zu unserer pom.xml hinzu :

 org.glassfish.jersey.ext jersey-bean-validation 2.27 

Wir können die neueste Version von Maven Central erhalten.

3.2. Server konfigurieren

In Jersey registrieren wir normalerweise die Erweiterungsfunktion, die wir in unserer benutzerdefinierten Ressourcenkonfigurationsklasse verwenden möchten.

Für die Bean-Validierungserweiterung ist diese Registrierung jedoch nicht erforderlich. Glücklicherweise ist dies eine der wenigen Erweiterungen, die das Jersey-Framework automatisch registriert.

Um Validierungsfehler an den Client zu senden, fügen wir unserer benutzerdefinierten Ressourcenkonfiguration eine Servereigenschaft hinzu :

public ViewApplicationConfig() { packages("com.baeldung.jersey.server"); property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); } 

4. Überprüfen der JAX-RS-Ressourcenmethoden

In diesem Abschnitt werden zwei verschiedene Methoden zum Überprüfen von Eingabeparametern mithilfe von Einschränkungsanmerkungen erläutert:

  • Verwenden der integrierten Bean Validation API-Einschränkungen
  • Erstellen einer benutzerdefinierten Einschränkung und eines Validators

4.1. Verwenden integrierter Einschränkungsanmerkungen

Beginnen wir mit den integrierten Anmerkungen zu Einschränkungen:

@POST @Path("/create") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public void createFruit( @NotNull(message = "Fruit name must not be null") @FormParam("name") String name, @NotNull(message = "Fruit colour must not be null") @FormParam("colour") String colour) { Fruit fruit = new Fruit(name, colour); SimpleStorageService.storeFruit(fruit); } 

In diesem Beispiel erstellen wir eine neue Frucht mit zwei Formularparametern, Name und Farbe . Wir verwenden die Annotation @NotNull, die bereits Teil der Bean Validation API ist.

Dies legt eine einfache Nicht-Null-Einschränkung für unsere Formularparameter fest. Wenn einer der Parameter null ist , wird die in der Anmerkung deklarierte Nachricht zurückgegeben .

Natürlich werden wir dies mit einem Unit-Test demonstrieren:

@Test public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() { Form form = new Form(); form.param("name", "apple"); form.param("colour", null); Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED) .post(Entity.form(form)); assertEquals("Http Response should be 400 ", 400, response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null")); } 

Im obigen Beispiel verwenden wir die JerseyTest- Unterstützungsklasse, um unsere Fruchtressource zu testen . Wir senden eine POST - Anforderung mit einer Null - Farbe und prüfen, ob die Antwort der erwarteten Nachricht enthält.

Eine Liste der integrierten Validierungsbeschränkungen finden Sie in den Dokumenten.

4.2. Definieren einer benutzerdefinierten Einschränkungsanmerkung

Manchmal müssen wir komplexere Einschränkungen auferlegen. Wir können dies tun, indem wir unsere eigene benutzerdefinierte Anmerkung definieren.

Stellen wir uns anhand unseres einfachen Beispiels für die Frucht-API vor, wir müssen überprüfen, ob alle Früchte eine gültige Seriennummer haben:

@PUT @Path("/update") @Consumes("application/x-www-form-urlencoded") public void updateFruit(@SerialNumber @FormParam("serial") String serial) { //... } 

In diesem Beispiel muss der Parameter serial die durch @SerialNumber definierten Einschränkungen erfüllen , die wir als Nächstes definieren.

Wir definieren zuerst die Einschränkungsanmerkung:

@Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = { SerialNumber.Validator.class }) public @interface SerialNumber { String message() default "Fruit serial number is not valid"; Class[] groups() default {}; Class[] payload() default {}; } 

Als nächstes definieren wir die Validator-Klasse SerialNumber.Validator :

public class Validator implements ConstraintValidator { @Override public void initialize(SerialNumber serial) { } @Override public boolean isValid(String serial, ConstraintValidatorContext constraintValidatorContext) { String serialNumRegex = "^\\d{3}-\\d{3}-\\d{4}$"; return Pattern.matches(serialNumRegex, serial); } } 

Der entscheidende Punkt hierbei ist, dass die Validator- Klasse ConstraintValidator implementieren muss, wobei T der Werttyp ist, den wir validieren möchten, in unserem Fall ein String .

Schließlich implementieren wir unsere benutzerdefinierte Validierungslogik in der isValid- Methode .

5. Ressourcenvalidierung

Darüber hinaus können wir mit der Bean-Validierungs-API Objekte mithilfe der Annotation @Valid validieren .

Im nächsten Abschnitt werden zwei verschiedene Methoden zum Überprüfen von Ressourcenklassen mithilfe dieser Anmerkung erläutert:

  • Fordern Sie zunächst eine Ressourcenüberprüfung an
  • Zweitens die Validierung der Antwortressourcen

Beginnen wir mit dem Hinzufügen der Annotation @Min zu unserem Fruit- Objekt:

@XmlRootElement public class Fruit { @Min(value = 10, message = "Fruit weight must be 10 or greater") private Integer weight; //... } 

5.1. Ressourcenüberprüfung anfordern

Zunächst aktivieren wir die Validierung mit @Valid in unserer FruitResource- Klasse:

@POST @Path("/create") @Consumes("application/json") public void createFruit(@Valid Fruit fruit) { SimpleStorageService.storeFruit(fruit); } 

Wenn wir im obigen Beispiel versuchen, eine Frucht mit einem Gewicht von weniger als 10 zu erstellen, wird ein Validierungsfehler angezeigt.

5.2. Validierung der Antwortressourcen

Ebenso sehen wir im nächsten Beispiel, wie eine Antwortressource validiert wird:

@GET @Valid @Produces("application/json") @Path("/search/{name}") public Fruit findFruitByName(@PathParam("name") String name) { return SimpleStorageService.findByName(name); }

Beachten Sie, wie wir dieselbe @ Valid- Annotation verwenden. Dieses Mal verwenden wir es jedoch auf der Ebene der Ressourcenmethoden, um sicherzustellen, dass die Antwort gültig ist.

6. Benutzerdefinierter Ausnahmebehandler

In diesem letzten Teil wird kurz erläutert, wie Sie einen benutzerdefinierten Ausnahmebehandler erstellen. Dies ist nützlich, wenn wir eine benutzerdefinierte Antwort zurückgeben möchten, wenn wir gegen eine bestimmte Einschränkung verstoßen.

Let's begin by defining our FruitExceptionMapper:

public class FruitExceptionMapper implements ExceptionMapper { @Override public Response toResponse(ConstraintViolationException exception) { return Response.status(Response.Status.BAD_REQUEST) .entity(prepareMessage(exception)) .type("text/plain") .build(); } private String prepareMessage(ConstraintViolationException exception) { StringBuilder message = new StringBuilder(); for (ConstraintViolation cv : exception.getConstraintViolations()) { message.append(cv.getPropertyPath() + " " + cv.getMessage() + "\n"); } return message.toString(); } }

First of all, we define a custom exception mapping provider. In order to do this, we implement the ExceptionMapper interface using a ConstraintViolationException.

Hence, we'll see that when this exception is thrown the toResponse method of our custom exception mapper instance will be invoked .

Also, in this simple example, we iterate through all the violations and append each property and message to be sent back in the response.

Next, in order to use our custom exception mapper we need to register our provider:

@Override protected Application configure() { ViewApplicationConfig config = new ViewApplicationConfig(); config.register(FruitExceptionMapper.class); return config; }

Finally, we add an endpoint to return an invalid Fruit to show the exception handler in action:

@GET @Produces(MediaType.TEXT_HTML) @Path("/exception") @Valid public Fruit exception() { Fruit fruit = new Fruit(); fruit.setName("a"); fruit.setColour("b"); return fruit; } 

7. Conclusion

Zusammenfassend haben wir in diesem Tutorial die Erweiterung der Jersey Bean Validation API untersucht.

Zunächst haben wir vorgestellt, wie die Bean Validation API in Jersey verwendet werden kann. Außerdem haben wir uns angesehen, wie eine Beispielwebanwendung konfiguriert wird.

Schließlich haben wir uns verschiedene Möglichkeiten angesehen, die Validierung mit Jersey durchzuführen und einen benutzerdefinierten Ausnahmebehandler zu schreiben.

Wie immer ist der vollständige Quellcode des Artikels auf GitHub verfügbar.