|
<?xml version="1.0"?> |
|
<!-- |
|
|
|
Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved. |
|
|
|
This program and the accompanying materials are made available under the |
|
terms of the Eclipse Public License v. 2.0, which is available at |
|
http://www.eclipse.org/legal/epl-2.0. |
|
|
|
This Source Code may also be made available under the following Secondary |
|
Licenses when the conditions for such availability set forth in the |
|
Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
|
version 2 with the GNU Classpath Exception, which is available at |
|
https://www.gnu.org/software/classpath/license.html. |
|
|
|
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
|
|
|
--> |
|
|
|
<!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]> |
|
<chapter xmlns="http://docbook.org/ns/docbook" |
|
version="5.0" |
|
xml:lang="en" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:xi="http://www.w3.org/2001/XInclude" |
|
xmlns:xlink="http://www.w3.org/1999/xlink" |
|
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd |
|
http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd" |
|
xml:id="bean-validation"> |
|
|
|
<title>Bean Validation Support</title> |
|
|
|
<para> |
|
Validation is a process of verifying that some data obeys one or more pre-defined constraints. This chapter describes |
|
support for &bv.project.link; in Jersey in terms of the needed dependencies, configuration, registration and usage. |
|
For more detailed description on how JAX-RS provides native support for validating resource classes based on the |
|
Bean Validation refer to the chapter in the <link xlink:href="http://jcp.org/en/jsr/detail?id=339">JAX-RS spec</link>. |
|
</para> |
|
|
|
<section> |
|
<title>Bean Validation Dependencies</title> |
|
|
|
<para> |
|
Bean Validation support in Jersey is provided as an extension module and needs to be mentioned explicitly in your |
|
&lit.pom.xml; file (in case of using Maven): |
|
|
|
<programlisting language="xml" linenumbering="unnumbered"><dependency> |
|
<groupId>org.glassfish.jersey.ext</groupId> |
|
<artifactId>jersey-bean-validation</artifactId> |
|
<version>&version;</version> |
|
</dependency></programlisting> |
|
|
|
<note> |
|
<para> |
|
If you're not using Maven make sure to have also all the transitive dependencies (see &jersey.ext.bean-validation.deps.link;) on |
|
the classpath. |
|
</para> |
|
</note> |
|
|
|
This module depends directly on |
|
<link xlink:href="http://hibernate.org/validator/">Hibernate Validator</link> |
|
which provides a most commonly used implementation of the Bean Validation API spec. |
|
</para> |
|
<para> |
|
If you want to use a different implementation of the Bean Validation API, use standard Maven mechanisms to exclude |
|
Hibernate Validator from the modules dependencies and add a dependency of your own. |
|
|
|
<programlisting language="xml" linenumbering="unnumbered"><dependency> |
|
<groupId>org.glassfish.jersey.ext</groupId> |
|
<artifactId>jersey-bean-validation</artifactId> |
|
<version>&version;</version> |
|
<exclusions> |
|
<exclusion> |
|
<groupId>org.hibernate</groupId> |
|
<artifactId>hibernate-validator</artifactId> |
|
</exclusion> |
|
</exclusions> |
|
</dependency></programlisting> |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Enabling Bean Validation in Jersey</title> |
|
|
|
<para> |
|
As stated in <xref linkend="deployment.autodiscoverable"/>, Jersey Bean Validation is one of the modules where you |
|
don't need to explicitly register its &lit.jaxrs.core.Feature;s (&jersey.ext.ValidationFeature;) on the |
|
server as its features are automatically discovered and registered when you add the |
|
&lit.jersey-bean-validation; module to your classpath. |
|
There are three Jersey specific properties that could disable automatic discovery and registration of Jersey Bean |
|
Validation integration module: |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>&jersey.common.CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE;</para> |
|
</listitem> |
|
<listitem> |
|
<para>&jersey.server.ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE;</para> |
|
</listitem> |
|
<listitem> |
|
<para>&jersey.server.ServerProperties.BV_FEATURE_DISABLE;</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<note> |
|
<para>Jersey does not support Bean Validation on the client at the moment.</para> |
|
</note> |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Configuring Bean Validation Support</title> |
|
|
|
<para> |
|
Configuration of Bean Validation support in Jersey is twofold - there are few specific properties that affects Jersey |
|
behaviour (e.g. sending validation error entities to the client) and then there is &jersey.ext.ValidationConfig; class |
|
that configures &bv.Validator; used for validating resources in JAX-RS application. |
|
</para> |
|
|
|
<para> |
|
To configure Jersey specific behaviour you can use the following properties: |
|
|
|
<variablelist> |
|
<varlistentry> |
|
<term>&jersey.server.ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK;</term> |
|
<listitem> |
|
<para> |
|
Disables &lit.bv.ValidateOnExecution; check. More on this is described in |
|
<xref linkend="bv.ValidateOnExecution" />. |
|
</para> |
|
</listitem> |
|
</varlistentry> |
|
<varlistentry> |
|
<term>&jersey.server.ServerProperties.BV_SEND_ERROR_IN_RESPONSE;</term> |
|
<listitem> |
|
<para> |
|
Enables sending validation errors in response entity to the client. More on this in |
|
<xref linkend="bv.ValidationError" />. |
|
</para> |
|
</listitem> |
|
</varlistentry> |
|
</variablelist> |
|
|
|
<example xml:id="bv.example.jersey.properties"> |
|
<title>Configuring Jersey specific properties for Bean Validation.</title> |
|
|
|
<programlisting language="java" linenumbering="numbered">new ResourceConfig() |
|
// Now you can expect validation errors to be sent to the client. |
|
.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true) |
|
// @ValidateOnExecution annotations on subclasses won't cause errors. |
|
.property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true) |
|
// Further configuration of ResourceConfig. |
|
.register( ... );</programlisting> |
|
</example> |
|
|
|
Customization of the &lit.bv.Validator; used in validation of resource classes/methods can be done using |
|
&lit.jersey.ext.ValidationConfig; class and exposing it via &jaxrs.ext.ContextResolver; mechanism as shown in |
|
<xref linkend="bv.example.ValidationConfig"/>. You can set custom instances for the following interfaces from |
|
the Bean Validation API: |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para> |
|
&bv.MessageInterpolator; - interpolates a given constraint violation message. |
|
</para> |
|
</listitem> |
|
<listitem> |
|
<para> |
|
&bv.TraversableResolver; - determines if a property can be accessed by the Bean Validation provider. |
|
</para> |
|
</listitem> |
|
<listitem> |
|
<para> |
|
&bv.ConstraintValidatorFactory; - instantiates a <literal>ConstraintValidator</literal> instance based |
|
off its class. Note that by setting a custom <literal>ConstraintValidatorFactory</literal> you may loose |
|
injection of available resources/providers at the moment. See <xref linkend="bv.injecting"/> how to |
|
handle this. |
|
</para> |
|
</listitem> |
|
<listitem> |
|
<para>&bv.ParameterNameProvider; - provides names for method and constructor parameters.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<example xml:id="bv.example.ValidationConfig"> |
|
<title>Using &lit.jersey.ext.ValidationConfig; to configure &lit.bv.Validator;.</title> |
|
|
|
<programlisting language="java">/** |
|
* Custom configuration of validation. This configuration defines custom: |
|
* <ul> |
|
* <li>ConstraintValidationFactory - so that validators are able to inject Jersey providers/resources.</li> |
|
* <li>ParameterNameProvider - if method input parameters are invalid, this class returns actual parameter names |
|
* instead of the default ones ({@code arg0, arg1, ..})</li> |
|
* </ul> |
|
*/ |
|
public class ValidationConfigurationContextResolver implements ContextResolver<ValidationConfig> { |
|
|
|
@Context |
|
private ResourceContext resourceContext; |
|
|
|
@Override |
|
public ValidationConfig getContext(final Class<?> type) { |
|
final ValidationConfig config = new ValidationConfig(); |
|
config.setConstraintValidatorFactory(resourceContext.getResource(InjectingConstraintValidatorFactory.class)); |
|
config.setParameterNameProvider(new CustomParameterNameProvider()); |
|
return config; |
|
} |
|
|
|
/** |
|
* See ContactCardTest#testAddInvalidContact. |
|
*/ |
|
private class CustomParameterNameProvider implements ParameterNameProvider { |
|
|
|
private final ParameterNameProvider nameProvider; |
|
|
|
public CustomParameterNameProvider() { |
|
nameProvider = Validation.byDefaultProvider().configure().getDefaultParameterNameProvider(); |
|
} |
|
|
|
@Override |
|
public List<String> getParameterNames(final Constructor<?> constructor) { |
|
return nameProvider.getParameterNames(constructor); |
|
} |
|
|
|
@Override |
|
public List<String> getParameterNames(final Method method) { |
|
// See ContactCardTest#testAddInvalidContact. |
|
if ("addContact".equals(method.getName())) { |
|
return Arrays.asList("contact"); |
|
} |
|
return nameProvider.getParameterNames(method); |
|
} |
|
} |
|
}</programlisting> |
|
|
|
<para>Register this class in your app:</para> |
|
|
|
<programlisting language="java">final Application application = new ResourceConfig() |
|
// Validation. |
|
.register(ValidationConfigurationContextResolver.class) |
|
// Further configuration. |
|
.register( ... );</programlisting> |
|
|
|
<note> |
|
<para>This code snippet is based on CustomConfigValidationTest (from Jersey's source codes)</para> |
|
</note> |
|
</example> |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Validating JAX-RS resources and methods</title> |
|
|
|
<para> |
|
JAX-RS specification states that constraint annotations are allowed in the same locations as the following |
|
annotations: &lit.jaxrs.MatrixParam;, &lit.jaxrs.QueryParam;, &lit.jaxrs.PathParam;, &lit.jaxrs.CookieParam;, |
|
&lit.jaxrs.HeaderParam; and &lit.jaxrs.core.Context;, <emphasis>except</emphasis> in class constructors and property |
|
setters. Specifically, they are allowed in resource method parameters, fields and property getters as well as |
|
resource classes, entity parameters and resource methods (return values). |
|
Jersey provides support for validation (see following sections) annotated input parameters and return value of the |
|
invoked resource method as well as validation of resource class (class constraints, field constraints) where this |
|
resource method is placed. |
|
Jersey does not support, and doesn't validate, constraints placed on constructors and Bean Validation groups (only |
|
<literal>Default</literal> group is supported at the moment). |
|
</para> |
|
|
|
<section> |
|
<title>Constraint Annotations</title> |
|
|
|
<para> |
|
The JAX-RS Server API provides support for extracting request values and mapping them into Java fields, |
|
properties and parameters using annotations such as &jaxrs.HeaderParam;, &jaxrs.QueryParam;, etc. It also |
|
supports mapping of the request entity bodies into Java objects via non-annotated parameters (i.e., parameters |
|
without any JAX-RS annotations). |
|
</para> |
|
<para> |
|
The Bean Validation specification supports the use of <emphasis>constraint annotations</emphasis> |
|
as a way of declarative validating beans, method parameters and method returned values. For example, consider |
|
resource class from <xref linkend="bv.example.constraints"/> augmented with constraint annotations. |
|
|
|
<example xml:id="bv.example.constraints"> |
|
<title>Constraint annotations on input parameters</title> |
|
<programlisting language="java">@Path("/") |
|
class MyResourceClass { |
|
|
|
@POST |
|
@Consumes("application/x-www-form-urlencoded") |
|
public void registerUser( |
|
@NotNull @FormParam("firstName") String firstName, |
|
@NotNull @FormParam("lastName") String lastName, |
|
@Email @FormParam("email") String email) { |
|
... |
|
} |
|
}</programlisting> |
|
</example> |
|
|
|
The annotations &lit.bv.NotNull; and &lit.bv.Email; impose additional constraints on the form parameters |
|
<literal>firstName</literal>, <literal>lastName</literal> and <literal>email</literal>. The &lit.bv.NotNull; |
|
constraint is built-in to the Bean Validation API; the &lit.bv.Email; |
|
constraint is assumed to be user defined in the example above. These constraint annotations are not restricted to |
|
method parameters, they can be used in any location in which JAX-RS binding annotations are allowed with the |
|
exception of constructors and property setters. |
|
</para> |
|
<para> |
|
Rather than using method parameters, the <literal>MyResourceClass</literal> shown above could have been written |
|
as in <xref linkend="bv.example.constraints.fields"/>. |
|
|
|
<example xml:id="bv.example.constraints.fields"> |
|
<title>Constraint annotations on fields</title> |
|
<programlisting language="java">@Path("/") |
|
class MyResourceClass { |
|
|
|
@NotNull |
|
@FormParam("firstName") |
|
private String firstName; |
|
|
|
@NotNull |
|
@FormParam("lastName") |
|
private String lastName; |
|
|
|
private String email; |
|
|
|
@FormParam("email") |
|
public void setEmail(String email) { |
|
this.email = email; |
|
} |
|
|
|
@Email |
|
public String getEmail() { |
|
return email; |
|
} |
|
|
|
... |
|
}</programlisting> |
|
</example> |
|
|
|
Note that in this version, <literal>firstName</literal> and <literal>lastName</literal> are fields initialized |
|
via injection and <literal>email</literal> is a resource class property. Constraint annotations on properties are |
|
specified in their corresponding getters. |
|
</para> |
|
<para> |
|
Constraint annotations are also allowed on resource classes. In addition to annotating fields and properties, an |
|
annotation can be defined for the entire class. Let us assume that <literal>@NonEmptyNames</literal> validates |
|
that one of the two <emphasis>name</emphasis> fields in <literal>MyResourceClass</literal> is provided. Using |
|
such an annotation, the example above can be extended to look like <xref linkend="bv.example.constraints.class"/> |
|
|
|
<example xml:id="bv.example.constraints.class"> |
|
<title>Constraint annotations on class</title> |
|
<programlisting language="java">@Path("/") |
|
@NonEmptyNames |
|
class MyResourceClass { |
|
|
|
@NotNull |
|
@FormParam("firstName") |
|
private String firstName; |
|
|
|
@NotNull |
|
@FormParam("lastName") |
|
private String lastName; |
|
|
|
private String email; |
|
|
|
... |
|
}</programlisting> |
|
</example> |
|
|
|
Constraint annotations on resource classes are useful for defining cross-field and cross-property constraints. |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Annotation constraints and Validators</title> |
|
|
|
<para> |
|
Annotation constraints and validators are defined in accordance with the Bean Validation specification. |
|
The &lit.bv.Email; annotation used in <xref linkend="bv.example.constraints.fields"/> is defined using the |
|
Bean Validation &bv.Constraint; meta-annotation, see <xref linkend="bv.example.constraints.definition"/>. |
|
|
|
<example xml:id="bv.example.constraints.definition"> |
|
<title>Definition of a constraint annotation</title> |
|
<programlisting language="java">@Target({ METHOD, FIELD, PARAMETER }) |
|
@Retention(RUNTIME) |
|
@Constraint(validatedBy = EmailValidator.class) |
|
public @interface Email { |
|
|
|
String message() default "{com.example.validation.constraints.email}"; |
|
|
|
Class<?>[] groups() default {}; |
|
|
|
Class<? extends Payload>[] payload() default {}; |
|
}</programlisting> |
|
</example> |
|
|
|
The &lit.bv.Constraint; annotation must include a reference to the validator class that will be used to validate |
|
decorated values. The <literal>EmailValidator</literal> class must implement |
|
<literal>ConstraintValidator<Email, T></literal> where <literal>T</literal> is the type of values being |
|
validated, as described in <xref linkend="bv.example.validator.definition" />. |
|
|
|
<example xml:id="bv.example.validator.definition"> |
|
<title>Validator implementation.</title> |
|
<programlisting language="java">public class EmailValidator implements ConstraintValidator<Email, String> { |
|
|
|
public void initialize(Email email) { |
|
... |
|
} |
|
|
|
public boolean isValid(String value, ConstraintValidatorContext context) { |
|
... |
|
} |
|
}</programlisting> |
|
</example> |
|
|
|
Thus, <literal>EmailValidator</literal> applies to values annotated with &lit.bv.Email; that are of type |
|
<literal>String</literal>. Validators for other Java types can be defined for the same constraint annotation. |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Entity Validation</title> |
|
|
|
<para> |
|
Request entity bodies can be mapped to resource method parameters. There are two ways in which these entities can |
|
be validated. If the request entity is mapped to a Java bean whose class is decorated with Bean Validation |
|
annotations, then validation can be enabled using &bv.Valid; as in <xref linkend="bv.example.constraints.entity"/>. |
|
|
|
<example xml:id="bv.example.constraints.entity"> |
|
<title>Entity validation</title> |
|
<programlisting language="java">@StandardUser |
|
class User { |
|
|
|
@NotNull |
|
private String firstName; |
|
|
|
... |
|
} |
|
|
|
|
|
@Path("/") |
|
class MyResourceClass { |
|
|
|
@POST |
|
@Consumes("application/xml") |
|
public void registerUser(@Valid User user) { |
|
... |
|
} |
|
}</programlisting> |
|
</example> |
|
|
|
In this case, the validator associated with <literal>@StandardUser</literal> (as well as those for non-class |
|
level constraints like &lit.bv.NotNull;) will be called to verify the request entity mapped to |
|
<literal>user</literal>. |
|
</para> |
|
<para> |
|
Alternatively, a new annotation can be defined and used directly on the resource |
|
method parameter (<xref linkend="bv.example.constraints.entity2"/>). |
|
|
|
<example xml:id="bv.example.constraints.entity2"> |
|
<title>Entity validation 2</title> |
|
<programlisting language="java">@Path("/") |
|
class MyResourceClass { |
|
|
|
@POST |
|
@Consumes("application/xml") |
|
public void registerUser(@PremiumUser User user) { |
|
... |
|
} |
|
}</programlisting> |
|
</example> |
|
|
|
In the example above, <literal>@PremiumUser</literal> rather than <literal>@StandardUser</literal> will be used |
|
to validate the request entity. These two ways in which validation of entities can be triggered can also be |
|
combined by including &lit.bv.Valid; in the list of constraints. The presence of &lit.bv.Valid; will trigger |
|
validation of <emphasis>all</emphasis> the constraint annotations decorating a Java bean class. |
|
</para> |
|
<para> |
|
Response entity bodies returned from resource methods can be validated in a similar manner by annotating the |
|
resource method itself. To exemplify, assuming both <literal>@StandardUser</literal> and |
|
<literal>@PremiumUser</literal> are required to be checked before returning a user, the |
|
<literal>getUser</literal> method can be annotated as shown in |
|
<xref linkend="bv.example.constraints.entity.response"/>. |
|
<example xml:id="bv.example.constraints.entity.response"> |
|
<title>Response entity validation</title> |
|
<programlisting language="java">@Path("/") |
|
class MyResourceClass { |
|
|
|
@GET |
|
@Path("{id}") |
|
@Produces("application/xml") |
|
@Valid @PremiumUser |
|
public User getUser(@PathParam("id") String id) { |
|
User u = findUser(id); |
|
return u; |
|
} |
|
|
|
... |
|
}</programlisting> |
|
</example> |
|
|
|
Note that <literal>@PremiumUser</literal> is explicitly listed and <literal>@StandardUser</literal> is triggered |
|
by the presence of the &lit.bv.Valid; annotation - see definition of <literal>User</literal> class earlier in |
|
this section. |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Annotation Inheritance</title> |
|
|
|
<para> |
|
The rules for inheritance of constraint annotation are defined in Bean Validation specification. It is worth |
|
noting that these rules are incompatible with those defined by JAX-RS. Generally speaking, constraint |
|
annotations in Bean Validation are cumulative (can be strengthen) across a given type hierarchy while JAX-RS |
|
annotations are inherited or, overridden and ignored. |
|
</para> |
|
<para> |
|
For Bean Validation annotations Jersey follows the constraint annotation rules defined in the Bean Validation |
|
specification. |
|
</para> |
|
</section> |
|
</section> |
|
|
|
<section xml:id="bv.ValidateOnExecution"> |
|
<title>@ValidateOnExecution</title> |
|
|
|
<para> |
|
According to Bean Validation specification, validation is enabled by default only for the so called |
|
<emphasis>constrained</emphasis> methods. Getter |
|
methods as defined by the Java Beans specification are not constrained methods, so they will not be validated by |
|
default. The special annotation &lit.bv.ValidateOnExecution; can be used to selectively enable |
|
and disable validation. For example, you can enable validation on method <literal>getEmail</literal> shown in |
|
<xref linkend="bv.example.validateonexecution"/>. |
|
<example xml:id="bv.example.validateonexecution"> |
|
<title>Validate getter on execution</title> |
|
|
|
<programlisting language="java">@Path("/") |
|
class MyResourceClass { |
|
|
|
@Email |
|
@ValidateOnExecution |
|
public String getEmail() { |
|
return email; |
|
} |
|
|
|
... |
|
}</programlisting> |
|
</example> |
|
|
|
The default value for the <literal>type</literal> attribute of &lit.bv.ValidateOnExecution; is |
|
<literal>IMPLICIT</literal> which results in method <literal>getEmail</literal> being validated. |
|
<note> |
|
<para> |
|
According to Bean Validation specification &lit.bv.ValidateOnExecution; cannot be overridden once is |
|
declared on a method (i.e. in subclass/sub-interface) and in this situations a |
|
<literal>ValidationException</literal> should be raised. This default behaviour can be suppressed by |
|
setting &jersey.server.ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK; |
|
property (Jersey specific) to &lit.true;. |
|
</para> |
|
</note> |
|
</para> |
|
</section> |
|
|
|
<section xml:id="bv.injecting"> |
|
<title>Injecting</title> |
|
|
|
<para> |
|
Jersey allows you to inject registered resources/providers into your &bv.ConstraintValidator; implementation and you |
|
can inject &bv.Configuration;, &bv.ValidatorFactory; and &bv.Validator; as required by Bean Validation spec. |
|
|
|
<note> |
|
<para> |
|
Injected &bv.Configuration;, &bv.ValidatorFactory; and &bv.Validator; do not inherit configuration provided |
|
by &jersey.ext.ValidationConfig; and need to be configured manually. |
|
</para> |
|
</note> |
|
|
|
Injection of JAX-RS components into &lit.bv.ConstraintValidator;s is supported via a custom |
|
&lit.bv.ConstraintValidatorFactory; provided by Jersey. An example is shown in |
|
<xref linkend="bv.examples.injecting"/>. |
|
|
|
<example xml:id="bv.examples.injecting"> |
|
<title>Injecting UriInfo into a ConstraintValidator</title> |
|
<programlisting language="java">public class EmailValidator implements ConstraintValidator<Email, String> { |
|
|
|
@Context |
|
private UriInfo uriInfo; |
|
|
|
public void initialize(Email email) { |
|
... |
|
} |
|
|
|
public boolean isValid(String value, ConstraintValidatorContext context) { |
|
// Use UriInfo. |
|
|
|
... |
|
} |
|
}</programlisting> |
|
</example> |
|
</para> |
|
<para> |
|
Using a custom &bv.ConstraintValidatorFactory; of your own disables registration of the one provided by Jersey |
|
and injection support for resources/providers (if needed) has to be provided by this new implementation. |
|
<xref linkend="bv.examples.injecting.factory"/> shows how this can be achieved. |
|
|
|
<example xml:id="bv.examples.injecting.factory"> |
|
<title>Support for injecting Jersey's resources/providers via ConstraintValidatorFactory.</title> |
|
<programlisting language="java">public class InjectingConstraintValidatorFactory implements ConstraintValidatorFactory { |
|
|
|
@Context |
|
private ResourceContext resourceContext; |
|
|
|
@Override |
|
public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> key) { |
|
return resourceContext.getResource(key); |
|
} |
|
|
|
@Override |
|
public void releaseInstance(final ConstraintValidator<?, ?> instance) { |
|
// NOOP |
|
} |
|
}</programlisting> |
|
</example> |
|
<note> |
|
<para> |
|
This behaviour may likely change in one of the next version of Jersey to remove the need of |
|
manually providing support for injecting resources/providers from Jersey in your own |
|
&lit.bv.ConstraintValidatorFactory; implementation code. |
|
</para> |
|
</note> |
|
</para> |
|
</section> |
|
|
|
<section> |
|
<title>Error Reporting</title> |
|
|
|
<para> |
|
Bean Validation specification defines a small hierarchy of exceptions (they all inherit from |
|
&bv.ValidationException;) that could be thrown during initialization of validation engine or (for our case more |
|
importantly) during validation of input/output values (&bv.ConstraintViolationException;). |
|
If a thrown exception is a subclass of &lit.bv.ValidationException; <emphasis>except</emphasis> |
|
&lit.bv.ConstraintViolationException; then this exception is mapped to a HTTP response with status code 500 |
|
(Internal Server Error). |
|
On the other hand, when a &lit.bv.ConstraintViolationException; is throw two different status code would be returned: |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>500 (Internal Server Error)</para> |
|
<para>If the exception was thrown while validating a method return type.</para> |
|
</listitem> |
|
<listitem> |
|
<para>400 (Bad Request)</para> |
|
<para>Otherwise.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</para> |
|
|
|
<section xml:id="bv.ValidationError"> |
|
<title>ValidationError</title> |
|
|
|
<para> |
|
By default, (during mapping &lit.bv.ConstraintViolationException;s) Jersey doesn't return any entities that would |
|
include validation errors to the client. This default behaviour could be changed by enabling |
|
&jersey.server.ServerProperties.BV_SEND_ERROR_IN_RESPONSE; property in your application |
|
(<xref linkend="bv.example.jersey.properties"/>). |
|
When this property is enabled then our custom &jaxrs.ext.ExceptionMapper; (that is handling |
|
&lit.bv.ValidationException;s) would transform &lit.bv.ConstraintViolationException;(s) into |
|
&jersey.ext.ValidationError;(s) and set this object (collection) as the new response entity which Jersey is |
|
able to sent to the client. |
|
Four &lit.jaxrs.core.MediaType;s are currently supported when sending &lit.jersey.ext.ValidationError;s to the |
|
client: |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>text/plain</literal></para> |
|
</listitem> |
|
<listitem> |
|
<para><literal>text/html</literal></para> |
|
</listitem> |
|
<listitem> |
|
<para><literal>application/xml</literal></para> |
|
</listitem> |
|
<listitem> |
|
<para><literal>application/json</literal></para> |
|
<note> |
|
<para> |
|
Note: You need to register one of the JSON (JAXB) providers (e.g. |
|
<link linkend='json.moxy'>MOXy</link>) to marshall validation errors to JSON. |
|
</para> |
|
</note> |
|
</listitem> |
|
</itemizedlist> |
|
</para> |
|
<para> |
|
Let's take a look at &jersey.ext.ValidationError; class to see which properties are send to the client: |
|
|
|
<programlisting language="java">@XmlRootElement |
|
public final class ValidationError { |
|
|
|
private String message; |
|
|
|
private String messageTemplate; |
|
|
|
private String path; |
|
|
|
private String invalidValue; |
|
|
|
... |
|
}</programlisting> |
|
|
|
The <literal>message</literal> property is the interpolated error message, <literal>messageTemplate</literal> |
|
represents a non-interpolated error message (or key from your constraint definition e.g. |
|
<literal>{jakarta.validation.constraints.NotNull.message}</literal>), <literal>path</literal> contains information |
|
about the path in the validated object graph to the property holding invalid value and |
|
<literal>invalidValue</literal> is the string representation of the invalid value itself. |
|
</para> |
|
<para> |
|
Here are few examples of &lit.jersey.ext.ValidationError; messages sent to client: |
|
|
|
<example> |
|
<title>&lit.jersey.ext.ValidationError; to <literal>text/plain</literal></title> |
|
|
|
<screen language="text" linenumbering="unnumbered">HTTP/1.1 500 Internal Server Error |
|
Content-Length: 114 |
|
Content-Type: text/plain |
|
Vary: Accept |
|
Server: Jetty(11.0.0.beta3) |
|
|
|
Contact with given ID does not exist. (path = ContactCardResource.getContact.<return value>, invalidValue = null)</screen> |
|
</example> |
|
|
|
<example> |
|
<title>&lit.jersey.ext.ValidationError; to <literal>text/html</literal></title> |
|
<screen language="xml" linenumbering="unnumbered">HTTP/1.1 500 Internal Server Error |
|
Content-Length: ... |
|
Content-Type: text/plain |
|
Vary: Accept |
|
Server: Jetty(11.0.0.beta3) |
|
|
|
<![CDATA[<div class="validation-errors"> |
|
<div class="validation-error"> |
|
<span class="message">Contact with given ID does not exist.</span> |
|
( |
|
<span class="path"> |
|
<strong>path</strong> |
|
= ContactCardResource.getContact.<return value> |
|
</span> |
|
, |
|
<span class="invalid-value"> |
|
<strong>invalidValue</strong> |
|
= null |
|
</span> |
|
) |
|
</div> |
|
</div>]]></screen> |
|
</example> |
|
|
|
<example> |
|
<title>&lit.jersey.ext.ValidationError; to <literal>application/xml</literal></title> |
|
<screen language="xml" linenumbering="unnumbered">HTTP/1.1 500 Internal Server Error |
|
Content-Length: ... |
|
Content-Type: text/plain |
|
Vary: Accept |
|
Server: Jetty(11.0.0.beta3) |
|
|
|
<![CDATA[<?xml version="1.0" encoding="UTF-8"?> |
|
<validationErrors> |
|
<validationError> |
|
<message>Contact with given ID does not exist.</message> |
|
<messageTemplate>{contact.does.not.exist}</messageTemplate> |
|
<path>ContactCardResource.getContact.<return value></path> |
|
</validationError> |
|
</validationErrors>]]></screen> |
|
</example> |
|
|
|
<example> |
|
<title>&lit.jersey.ext.ValidationError; to <literal>application/json</literal></title> |
|
<screen language="xml" linenumbering="unnumbered">HTTP/1.1 500 Internal Server Error |
|
Content-Length: 174 |
|
Content-Type: application/json |
|
Vary: Accept |
|
Server: Jetty(11.0.0.beta3) |
|
|
|
[ { |
|
"message" : "Contact with given ID does not exist.", |
|
"messageTemplate" : "{contact.does.not.exist}", |
|
"path" : "ContactCardResource.getContact.<return value>" |
|
} ]</screen> |
|
</example> |
|
</para> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Example</title> |
|
|
|
<para>Examples are being processed to comply with Jakarta EE standards.</para> |
|
</section> |
|
</chapter> |