blob: 0acc5e0a9d539c29673239ecad4adcdb1e8380c0 [file] [log] [blame]
<?xml version="1.0"?>
<!--
Copyright (c) 2013, 2018 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;
<!ENTITY jersey.github.ef.example.link "<link xlink:href='&jersey.github.examples.uri;/entity-filtering'>Entity Filtering example</link>">
<!ENTITY jersey.github.ef.security.example.link "<link xlink:href='&jersey.github.examples.uri;/entity-filtering-security'>Entity Filtering example (with security annotations)</link>">
<!ENTITY jersey.github.ef.selectable.example.link "<link xlink:href='&jersey.github.examples.uri;/entity-filtering-selectable'>Entity Filtering example (based on dynamic and configurable query parameters)</link>">
]>
<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="entity-filtering">
<title>Entity Data Filtering</title>
<para>
Support for Entity Filtering in Jersey introduces a convenient facility for reducing the amount of data exchanged over
the wire between client and server without a need to create specialized data view components. The main idea behind this
feature is to give you APIs that will let you to selectively filter out any non-relevant data from the marshalled object
model before sending the data to the other party based on the context of the particular message exchange.
This way, only the necessary or relevant portion of the data is transferred over the network with each client request
or server response, without a need to create special facade models for transferring these limited subsets of the model
data.
</para>
<para>
Entity filtering feature allows you to define your own entity-filtering rules for your entity classes based on the
current context (e.g. matched resource method) and keep these rules in one place (directly in your domain model).
With Jersey entity filtering facility it is also possible to assign security access rules to entity classes properties
and property accessors.
</para>
<para>
We will first explain the main concepts and then we will explore the entity filtering feature topics from a perspective
of basic use-cases,
<itemizedlist>
<listitem>
<para><xref linkend="ef.annotations"/></para>
</listitem>
<listitem>
<para><xref linkend="ef.security.annotations"/></para>
</listitem>
<listitem>
<para><xref linkend="ef.selectable.annotations"/></para>
</listitem>
</itemizedlist>
as well as some more complex ones.
<itemizedlist>
<listitem>
<para><xref linkend="ef.custom.annotations"/></para>
</listitem>
</itemizedlist>
</para>
<note>
<para>
Jersey entity filtering feature is supported via Jersey extension modules listed in <xref linkend="ef.modules"/>.
</para>
</note>
<section>
<title>Enabling and configuring Entity Filtering in your application</title>
<para>
Entity Filtering 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">&lt;dependency&gt;
&lt;groupId&gt;org.glassfish.jersey.ext&lt;/groupId&gt;
&lt;artifactId&gt;jersey-entity-filtering&lt;/artifactId&gt;
&lt;version&gt;&version;&lt;/version&gt;
&lt;/dependency&gt;</programlisting>
<note>
<para>
If you're not using Maven make sure to have also all the transitive dependencies
(see &jersey.ext.entity-filtering.deps.link;) on the classpath.
</para>
</note>
</para>
<para>
The entity-filtering extension module provides three &lit.jaxrs.core.Feature;s which you can register into server/client
runtime in prior to use Entity Filtering in an application:
<itemizedlist>
<listitem>
<para>&jersey.message.filtering.EntityFilteringFeature;</para>
<para>
Filtering based on entity-filtering annotations (or i.e. external configuration file) created using
&jersey.message.filtering.EntityFiltering; meta-annotation.
</para>
</listitem>
<listitem>
<para>&jersey.message.filtering.SecurityEntityFilteringFeature;</para>
<para>Filtering based on security (<literal>javax.annotation.security</literal>) and entity-filtering
annotations.</para>
</listitem>
<listitem>
<para>&jersey.message.filtering.SelectableEntityFilteringFeature;</para>
<para>Filtering based on dynamic and configurable query parameters.</para>
</listitem>
</itemizedlist>
If you want to use both entity-filtering annotations and security annotations for entity data filtering it is enough
to register &lit.jersey.message.filtering.SecurityEntityFilteringFeature; as this feature registers also
&lit.jersey.message.filtering.EntityFilteringFeature;.
</para>
<para>
Entity-filtering currently recognizes one property that can be passed into the &jaxrs.core.Configuration; instance
(client/server):
<itemizedlist>
<listitem>
<para>&jersey.message.filtering.EntityFilteringFeature.ENTITY_FILTERING_SCOPE; - "<literal>jersey.config.entityFiltering.scope</literal>"</para>
<para>
Defines one or more annotations that should be used as entity-filtering scope when reading/writing an
entity.
</para>
</listitem>
</itemizedlist>
<note>
<para>
Processing of entity-filtering annotations to create an entity-filtering scope is defined by
following: "<literal>Request/Resource entity annotations</literal>" &gt;
"<literal>Configuration</literal>" &gt; "<literal>Resource method/class annotations</literal>"
(on server).
</para>
</note>
</para>
<para>
You can configure entity-filtering on server (basic + security examples) as follows:
<example xml:id="ef.example.server.registration">
<title>Registering and configuring entity-filtering feature on server.</title>
<programlisting language="java" linenumbering="numbered">new ResourceConfig()
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {ProjectDetailedView.Factory.get()})
// Register the EntityFilteringFeature.
.register(EntityFilteringFeature.class)
// Further configuration of ResourceConfig.
.register( ... );</programlisting>
</example>
<example xml:id="ef.example.server.security.registration">
<title>Registering and configuring entity-filtering feature with security annotations on server.</title>
<programlisting language="java" linenumbering="numbered">new ResourceConfig()
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {SecurityAnnotations.rolesAllowed("manager")})
// Register the SecurityEntityFilteringFeature.
.register(SecurityEntityFilteringFeature.class)
// Further configuration of ResourceConfig.
.register( ... );</programlisting>
</example>
<example xml:id="ef.example.server.selectable.registration">
<title>Registering and configuring entity-filtering feature based on dynamic and configurable query parameters.</title>
<programlisting language="java" linenumbering="numbered">new ResourceConfig()
// Set query parameter name for dynamic filtering
.property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "select")
// Register the SelectableEntityFilteringFeature.
.register(SelectableEntityFilteringFeature.class)
// Further configuration of ResourceConfig.
.register( ... );</programlisting>
</example>
</para>
<para>
Use similar steps to register entity-filtering on client:
<example xml:id="ef.example.client.registration">
<title>Registering and configuring entity-filtering feature on client.</title>
<programlisting language="java" linenumbering="numbered">final ClientConfig config = new ClientConfig()
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {ProjectDetailedView.Factory.get()})
// Register the EntityFilteringFeature.
.register(EntityFilteringFeature.class)
// Further configuration of ClientConfig.
.register( ... );
// Create new client.
final Client client = ClientClientBuilder.newClient(config);
// Use the client.</programlisting>
</example>
</para>
</section>
<section>
<title>Components used to describe Entity Filtering concepts</title>
<para>
In the next section the entity-filtering features will be illustrated on a project-tracking application that
contains three classes in it's domain model and few resources (only <literal>Project</literal> resource will be
shown in this chapter). The full source code for the example application can be found in Jersey
&jersey.github.ef.example.link;.
</para>
<para>
Suppose there are three domain model classes (or entities) in our model:
<literal>Project</literal>, <literal>User</literal> and <literal>Task</literal> (getters/setter are omitted for
brevity).
<example>
<title>Project</title>
<programlisting language="java" linenumbering="numbered">public class Project {
private Long id;
private String name;
private String description;
private List&lt;Task&gt; tasks;
private List&lt;User&gt; users;
// getters and setters
}</programlisting>
</example>
<example>
<title>User</title>
<programlisting language="java" linenumbering="numbered">public class User {
private Long id;
private String name;
private String email;
private List&lt;Project&gt; projects;
private List&lt;Task&gt; tasks;
// getters and setters
}</programlisting>
</example>
<example>
<title>Task</title>
<programlisting language="java" linenumbering="numbered">public class Task {
private Long id;
private String name;
private String description;
private Project project;
private User user;
// getters and setters
}</programlisting>
</example>
</para>
<para>
To retrieve the entities from server to client, we have created also a couple of JAX-RS resources from whose the
<literal>ProjectsResource</literal> is shown as example.
<example>
<title>ProjectsResource</title>
<programlisting language="java" linenumbering="numbered">@Path("projects")
@Produces("application/json")
public class ProjectsResource {
@GET
@Path("{id}")
public Project getProject(@PathParam("id") final Long id) {
return getDetailedProject(id);
}
@GET
public List&lt;Project&gt; getProjects() {
return getDetailedProjects();
}
}</programlisting>
</example>
</para>
</section>
<section xml:id="ef.annotations">
<title>Using custom annotations to filter entities</title>
<para>
Entity filtering via annotations is based on an &jersey.message.filtering.EntityFiltering; meta-annotation.
This meta-annotation is used to identify entity-filtering annotations that can be then attached to
<itemizedlist>
<listitem>
<para>domain model classes (supported on both, server and client sides), and</para>
</listitem>
<listitem>
<para>resource methods / resource classes (only on server side)</para>
</listitem>
</itemizedlist>
An example of entity-filtering annotation applicable to a class, field or method can be seen in
<xref linkend="ef.annotations.sample.annotation"/> below.
<example xml:id="ef.annotations.sample.annotation">
<title>ProjectDetailedView</title>
<programlisting language="java" linenumbering="numbered">@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EntityFiltering
public @interface ProjectDetailedView {
/**
* Factory class for creating instances of {@code ProjectDetailedView} annotation.
*/
public static class Factory
extends AnnotationLiteral&lt;ProjectDetailedView&gt;
implements ProjectDetailedView {
private Factory() {
}
public static ProjectDetailedView get() {
return new Factory();
}
}
}</programlisting>
</example>
</para>
<para>
Since creating annotation instances directly in Java code is not trivial, it is a good practice to provide an inner
annotation <literal>Factory</literal> class in each custom filtering annotation, through which new instances of
the annotation can be directly created. The annotation factory class can be created by extending the HK2
<literal>AnnotationLiteral</literal> class and implementing the annotation interface itself. It should also provide
a static factory method that will create and return a new instance of the <literal>Factory</literal> class when
invoked. Such annotation instances can be then passed to the client and server run-times to define or override
entity-filtering scopes.
</para>
<para>
By placing an entity-filtering annotation on an entity (class, fields, getters or setters) we define a so-called
<emphasis>entity-filtering scope</emphasis> for the entity. The purpose of entity-filtering scope is to identify
parts of the domain model that should be processed when the model is to be sent over the wire in a particular
entity-filtering scope. We distinguish between:
<itemizedlist>
<listitem>
<para>
global entity-filtering scope (defined by placing filtering annotation on a class itself), and
</para>
</listitem>
<listitem>
<para>
local entity-filtering scope (defined by placing filtering annotation on a field, getter or setter)
</para>
</listitem>
</itemizedlist>
Unannotated members of a domain model class are automatically added to all existing global entity-filtering scopes.
If there is no explicit global entity-filtering scope defined on a class a default scope is created for this class
to group these members.
</para>
<para>
Creating entity-filtering scopes using custom entity-filtering annotations in domain model classes is illustrated
in the following examples.
<example>
<title>Annotated Project</title>
<programlisting language="java" linenumbering="numbered">public class Project {
private Long id;
private String name;
private String description;
@ProjectDetailedView
private List&lt;Task&gt; tasks;
@ProjectDetailedView
private List&lt;User&gt; users;
// getters and setters
}</programlisting>
</example>
<example>
<title>Annotated User</title>
<programlisting language="java" linenumbering="numbered">public class User {
private Long id;
private String name;
private String email;
@UserDetailedView
private List&lt;Project&gt; projects;
@UserDetailedView
private List&lt;Task&gt; tasks;
// getters and setters
}</programlisting>
</example>
<example>
<title>Annotated Task</title>
<programlisting language="java" linenumbering="numbered">public class Task {
private Long id;
private String name;
private String description;
@TaskDetailedView
private Project project;
@TaskDetailedView
private User user;
// getters and setters
}</programlisting>
</example>
As you can see in the examples above, we have defined 3 separate scopes using <literal>@ProjectDetailedView</literal>,
<literal>@UserDetailedView</literal> and <literal>@TaskDetailedView</literal> annotations and we have applied
these scopes selectively to certain fields in the domain model classes.
</para>
<para>
Once the entity-filtering scopes are applied to the parts of a domain model, the entity filtering facility (when
enabled) will check the active scopes when the model is being sent over the wire, and filter out all parts from
the model for which there is no active scope set in the given context. Therefore, we need a way how to control
the scopes active in any given context in order to process the model data in a certain way (e.g. expose the detailed
view). We need to tell the server/client runtime which entity-filtering scopes we want to apply. There are 2 ways
how to do this for client-side and 3 ways for server-side:
<itemizedlist>
<listitem>
<para>Out-bound client request or server response programmatically created with entity-filtering annotations
that identify the scopes to be applied (available on both, client and server)</para>
</listitem>
<listitem>
<para>Property identifying the applied scopes passed through &jaxrs.core.Configuration;
(available on both, client and server)</para>
</listitem>
<listitem>
<para>Entity-filtering annotations identifying the applied scopes attached to a resource method or class
(server-side only)</para>
</listitem>
</itemizedlist>
When the multiple approaches are combined, the priorities of calculating the applied scopes are as follows:
<literal>Entity annotations in request or response</literal> &gt;
<literal>Property passed through Configuration</literal> &gt;
<literal>Annotations applied to a resource method or class</literal>.
</para>
<para>
In a graph of domain model objects, the entity-filtering scopes are applied to the root node as well as transitively
to all the child nodes. Fields and child nodes that do not match at least a single active scope are filtered out.
When the scope matching is performed, annotations applied to the domain model classes and fields
are used to compute the scope for each particular component of the model. If there are no annotations on the class
or it's fields, the default scope is assumed. During the filtering, first, the annotations on root model class
and it's fields are considered. For all composite fields that have not been filtered out, the annotations on the
referenced child class and it's fields are considered next, and so on.
</para>
<section>
<title>Server-side Entity Filtering</title>
<para>
To pass entity-filtering annotations via &jaxrs.core.Response; returned from a resource method you can leverage the
<link xlink:href='&jaxrs.javadoc.uri;/core/Response.ResponseBuilder.html#entity(java.lang.Object, java.lang.annotation.Annotation[])'>Response.ResponseBuilder#entity(Object, Annotation[])</link>
method. The next example illustrates this approach. You will also see why every custom entity-filtering
annotation should contain a factory for creating instances of the annotation.
<example>
<title>ProjectsResource - Response entity-filtering annotations</title>
<programlisting language="java" linenumbering="numbered">@Path("projects")
@Produces("application/json")
public class ProjectsResource {
@GET
public Response getProjects(@QueryParam("detailed") final boolean isDetailed) {
return Response
.ok()
.entity(new GenericEntity&lt;List&lt;Project&gt;&gt;(EntityStore.getProjects()) {},
isDetailed ? new Annotation[]{ProjectDetailedView.Factory.get()} : new Annotation[0])
.build();
}
}</programlisting>
</example>
Annotating a resource method / class is typically easier although it is less flexible and may require more
resource methods to be created to cover all the alternative use case scenarios. For example:
<example>
<title>ProjectsResource - Entity-filtering annotations on methods</title>
<programlisting language="java" linenumbering="numbered">@Path("projects")
@Produces("application/json")
public class ProjectsResource {
@GET
public List&lt;Project&gt; getProjects() {
return getDetailedProjects();
}
@GET
@Path("detailed")
@ProjectDetailedView
public List&lt;Project&gt; getDetailedProjects() {
return EntityStore.getProjects();
}
}</programlisting>
</example>
To see how entity-filtering scopes can be applied using a &lit.jaxrs.core.Configuration; property,
see the <xref linkend="ef.example.server.registration"/> example.
</para>
<para>
When a <literal>Project</literal> model from the example above is requested in a scope represented by
<literal>@ProjectDetailedView</literal> entity-filtering annotation, the <literal>Project</literal> model
data sent over the wire would contain:
<itemizedlist>
<listitem>
<para>
<literal>Project</literal> - <literal>id</literal>, <literal>name</literal>,
<literal>description</literal>, <literal>tasks</literal>, <literal>users</literal>
</para>
</listitem>
<listitem>
<para>
<literal>Task</literal> - <literal>id</literal>, <literal>name</literal>,
<literal>description</literal>
</para>
</listitem>
<listitem>
<para>
<literal>User</literal> - <literal>id</literal>, <literal>name</literal>, <literal>email</literal>
</para>
</listitem>
</itemizedlist>
Or, to illustrate this in JSON format:
<programlisting language="xml" linenumbering="numbered">{
"description" : "Jersey is the open source (under dual EPL+GPL license) JAX-RS 2.1 (JSR 370) production quality Reference Implementation for building RESTful Web services.",
"id" : 1,
"name" : "Jersey",
"tasks" : [ {
"description" : "Entity Data Filtering",
"id" : 1,
"name" : "ENT_FLT"
}, {
"description" : "OAuth 1 + 2",
"id" : 2,
"name" : "OAUTH"
} ],
"users" : [ {
"email" : "very@secret.com",
"id" : 1,
"name" : "Jersey Robot"
} ]
}</programlisting>
For the <emphasis>default entity-filtering scope</emphasis> the filtered model would look like:
<itemizedlist>
<listitem>
<para>
<literal>Project</literal> - <literal>id</literal>, <literal>name</literal>, <literal>description</literal>
</para>
</listitem>
</itemizedlist>
Or in JSON format:
<programlisting language="xml" linenumbering="numbered">{
"description" : "Jersey is the open source (under dual EPL+GPL license) JAX-RS 2.1 (JSR 370) production quality Reference Implementation for building RESTful Web services.",
"id" : 1,
"name" : "Jersey"
}</programlisting>
</para>
</section>
<section>
<title>Client-side Entity Filtering</title>
<para>
As mentioned above you can define applied entity-filtering scopes using a property set either in the client
run-time &lit.jaxrs.core.Configuration; (see <xref linkend="ef.example.client.registration"/>) or by
passing the entity-filtering annotations during a creation of an individual request to be sent to server.
<example>
<title>Client - Request entity-filtering annotations</title>
<programlisting language="java" linenumbering="numbered">ClientBuilder.newClient(config)
.target(uri)
.request()
.post(Entity.entity(project, new Annotation[] {ProjectDetailedView.Factory.get()}));</programlisting>
</example>
You can use the mentioned method with client injected into a resource as well.
<example>
<title>Client - Request entity-filtering annotations</title>
<programlisting language="java" linenumbering="numbered">@Path("clients")
@Produces("application/json")
public class ClientsResource {
@Uri("projects")
private WebTarget target;
@GET
public List&lt;Project&gt; getProjects() {
return target.request()
.post(Entity.entity(project, new Annotation[] {ProjectDetailedView.Factory.get()}));
}
}</programlisting>
</example>
</para>
</section>
</section>
<section xml:id="ef.security.annotations">
<title>Role-based Entity Filtering using (<literal>javax.annotation.security</literal>) annotations</title>
<para>
Filtering the content sent to the client (or server) based on the authorized security roles is a commonly
required use case. By registering &jersey.message.filtering.SecurityEntityFilteringFeature; you can
leverage the Jersey Entity Filtering facility in connection with standard
<literal>javax.annotation.security</literal> annotations exactly the same way as you would with custom
entity-filtering annotations described in previous chapters. Supported security annotations are:
<itemizedlist>
<listitem>
<para>&jee6.annotations.PermitAll;,</para>
</listitem>
<listitem>
<para>&jee6.annotations.RolesAllowed;, and</para>
</listitem>
<listitem>
<para>&jee6.annotations.DenyAll;</para>
</listitem>
</itemizedlist>
</para>
<para>
Although the mechanics of the Entity Data Filtering feature used for the security annotation-based filtering is
the same as with the entity-filtering annotations, the processing of security annotations differs in a few important
aspects:
<itemizedlist>
<listitem>
<para>
Custom &jaxrs.core.SecurityContext; should be set by a container request filter in order to use
&lit.jee6.annotations.RolesAllowed; for role-based filtering of domain model data (server-side)
</para>
</listitem>
<listitem>
<para>
There is no need to provide entity-filtering (or security) annotations on resource methods in order to
define entity-filtering scopes for &lit.jee6.annotations.RolesAllowed; that is applied to the domain model
components, as all the available roles for the current user are automatically determined using
the information from the provided &lit.jaxrs.core.SecurityContext; (server-side only).
</para>
</listitem>
</itemizedlist>
<note>
<para>
Instances of security annotations (to be used for programmatically defined scopes either on client or server)
can be created using one of the methods in the &jersey.message.filtering.SecurityAnnotations; factory class
that is part of the Jersey Entity Filtering API.
</para>
</note>
</para>
</section>
<section xml:id="ef.selectable.annotations">
<title>Entity Filtering based on dynamic and configurable query parameters</title>
<para>
Filtering the content sent to the client (or server) dynamically based on query parameters is another commonly
required use case. By registering &jersey.message.filtering.SelectableEntityFilteringFeature; you can
leverage the Jersey Entity Filtering facility in connection with query parameters exactly the same way as you would with custom
entity-filtering annotations described in previous chapters.
</para>
<para>
<example>
<title>Sever - Query Parameter driven entity-filtering</title>
<programlisting language="java" linenumbering="numbered">@XmlRootElement
public class Address {
private String streetAddress;
private String region;
private PhoneNumber phoneNumber;
}</programlisting>
</example>
</para>
<para>
Query parameters are supported in comma delimited "dot notation" style similar to <literal>BeanInfo</literal> objects
and Spring path expressions. As an example, the following URL:
<literal>http://jersey.example.com/addresses/51234?select=region,streetAddress</literal> may render only the address's
region and street address properties as in the following example:
</para>
<example>
<programlisting language="xml" linenumbering="numbered">{
"region" : "CA",
"streetAddress" : "1234 Fake St."
}</programlisting>
</example>
</section>
<section xml:id="ef.custom.annotations">
<title>Defining custom handling for entity-filtering annotations</title>
<para>
To create a custom entity-filtering annotation with special handling, i.e. an field aggregator annotation used
to annotate classes like the one in <xref linkend="ef.custom.annotations.annotation"/> it is, in most cases,
sufficient to implement and register the following SPI contracts:
<itemizedlist>
<listitem>
<para>&jersey.message.filtering.EntityProcessor;</para>
<para>Implementations of this SPI are invoked to process entity class and it's members. Custom
implementations can extend from &jersey.message.filtering.AbstractEntityProcessor;.</para>
</listitem>
<listitem>
<para>&jersey.message.filtering.ScopeResolver;</para>
<para>Implementations of this SPI are invoked to retrieve entity-filtering scopes from an array of
provided annotations.</para>
</listitem>
</itemizedlist>
<example xml:id="ef.custom.annotations.annotation">
<title>Entity-filtering annotation with custom meaning</title>
<programlisting language="java" linenumbering="numbered">@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@EntityFiltering
public @interface FilteringAggregator {
/**
* Entity-filtering scope to add given fields to.
*/
Annotation filteringScope();
/**
* Fields to be a part of the entity-filtering scope.
*/
String[] fields();
}</programlisting>
</example>
</para>
</section>
<section xml:id="ef.custom.providers">
<title>Supporting Entity Data Filtering in custom entity providers or frameworks</title>
<para>
To support Entity Data Filtering in custom entity providers (e.g. as in <xref linkend="ef.modules.custom"/>),
it is sufficient in most of the cases to implement and register the following SPI contracts:
<itemizedlist>
<listitem>
<para>&jersey.message.filtering.ObjectProvider;</para>
<para>
To be able to obtain an instance of a filtering object model your provider understands and can act on.
The implementations can extend &jersey.message.filtering.AbstractObjectProvider;.
</para>
</listitem>
<listitem>
<para>&jersey.message.filtering.ObjectGraphTransformer;</para>
<para>
To transform a read-only generic representation of a domain object model graph to be processed into
an entity-filtering object model your provider understands and can act on. The implementations can
extend &jersey.message.filtering.AbstractObjectProvider;.
</para>
</listitem>
</itemizedlist>
<example xml:id="ef.modules.custom">
<title>Entity Data Filtering support in MOXy JSON binding provider</title>
<programlisting language="java" linenumbering="numbered">@Singleton
public class FilteringMoxyJsonProvider extends ConfigurableMoxyJsonProvider {
@Inject
private Provider&lt;ObjectProvider&lt;ObjectGraph&gt;&gt; provider;
@Override
protected void preWriteTo(final Object object, final Class&lt;?&gt; type, final Type genericType, final Annotation[] annotations,
final MediaType mediaType, final MultivaluedMap&lt;String, Object&gt; httpHeaders,
final Marshaller marshaller) throws JAXBException {
super.preWriteTo(object, type, genericType, annotations, mediaType, httpHeaders, marshaller);
// Entity Filtering.
if (marshaller.getProperty(MarshallerProperties.OBJECT_GRAPH) == null) {
final Object objectGraph = provider.get().getFilteringObject(genericType, true, annotations);
if (objectGraph != null) {
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, objectGraph);
}
}
}
@Override
protected void preReadFrom(final Class&lt;Object&gt; type, final Type genericType, final Annotation[] annotations,
final MediaType mediaType, final MultivaluedMap&lt;String, String&gt; httpHeaders,
final Unmarshaller unmarshaller) throws JAXBException {
super.preReadFrom(type, genericType, annotations, mediaType, httpHeaders, unmarshaller);
// Entity Filtering.
if (unmarshaller.getProperty(MarshallerProperties.OBJECT_GRAPH) == null) {
final Object objectGraph = provider.get().getFilteringObject(genericType, false, annotations);
if (objectGraph != null) {
unmarshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, objectGraph);
}
}
}
}</programlisting>
</example>
</para>
</section>
<section xml:id="ef.modules">
<title>Modules with support for Entity Data Filtering</title>
<para>
List of modules from Jersey workspace that support Entity Filtering:
<itemizedlist>
<listitem>
<para>
<link linkend='json.moxy'>MOXy</link>
</para>
</listitem>
<listitem>
<para>
<link linkend='json.jackson'>Jackson (2.x)</link>
</para>
</listitem>
</itemizedlist>
</para>
<para>
In order to use Entity Filtering in mentioned modules you need to explicitly register either
&jersey.message.filtering.EntityFilteringFeature;, &jersey.message.filtering.SecurityEntityFilteringFeature;
or &jersey.message.filtering.SelectableEntityFilteringFeature; to activate Entity Filtering for particular module.
</para>
</section>
<section>
<title>Examples</title>
<para>
To see a complete working examples of entity-filtering feature refer to the:
<itemizedlist>
<listitem>
<para>&jersey.github.ef.example.link;</para>
</listitem>
<listitem>
<para>&jersey.github.ef.security.example.link;</para>
</listitem>
<listitem>
<para>&jersey.github.ef.selectable.example.link;</para>
</listitem>
</itemizedlist>
</para>
</section>
</chapter>