Serialization¶
Since individual web service resources (documentary units, repositories, etc) are comprised of many individual graph nodes, when resources are serialized we serialize their entire "subtree", rather than force the client to fetch each object in parts on a node by node basis. We also allow certain relationships between resources (particularly key "contextual" relationships, to be included in the payload of a resource when fetching its data.
These features make for a much less "chatty" REST interface and one which works on the level of resources proper, rather than the raw nodes and relationships of which they are comprised at the database level. Performing such "convenience" traversals during serialization does, however, involve some tradeoffs and complexities.
How serialization behavour is specified¶
Serialization semantics are specified using Java annotations on
adjacency methods present on the item domain model interfaces. Domain
model interfaces are "frames" for raw graph vertices that provide
convenience methods such as "getRepository()". The behaviour for these
interface methods (since they are obviously abstract) is provided by
Tinkerpop Frames
annotations such as
@Adjacency(label = ..., direction = Direction.IN)
which translate
the method call to the desired graph behaviour, by, in this case,
performing a graph traversal from a documentary unit node to that of its
repository.
EHRI-specific annotations¶
On top of the Tinkerpop Frames behaviour, the EHRI persistence layer adds two more annotations which control how framed domain models are serialized (to JSON, or XML, or whatever.) There are:
@Fetch
- when placed on an interface
get
method also decorated with@Adjacency
means this relationship should be traversed and items at the other end included in the serialized data. NB: Only mandatory properties for fetched items are included in the serialized data. @Dependent
- when placed on an interface
get
method also decorated with@Adjacency
means that that this item belongs to the target item. This is mainly used to sanity-check what data gets saved during de-serialization, but also affects the behaviour of serialization when deciding which data to include. Dependent items will be serialized with all data unless they belong to an item that is itself being included only in a@Fetch
traversal. @UniqueAdjacency
- an variation of Tinkerpop's
@Adjacency
which, when setting, adding, or removing relationships, ensures that the outgoing node can only have one relationship of the relationship's type connecting to the target node. When the single parameter is given it ensures that the outgoing node can only have a single relationship of that type to any other node. This annotation also provides additional functionality to return the number of relationships in the given direction when annotating methods named starting with the wordcount
.
Serialization parameters¶
There are a few parameters which affect the serializer's behaviour.
- Depth
- There is a default limit for the number of relationships to traverse when fetching related items. This prevents circular relationships (should they exist) causing infinite recursion, and prevents us sucking too much of the graph.
- 'Lite' mode
- This tells the serializer to only include mandatory properties for
all items (normally this behaviour only applies to items that are
@Fetch
ed.) - Dependent only
- This tells the serializer to ignore all
@Fetch
traversals and only include those that are@Dependent
. - Overriding Included Properties
- Sometimes you want to retrieve an item whilst insuring that a property
of a relation is serialized. By default (and the default is currently
fixed for the REST interface) only mandatory properties are included in
automatically serialized relations. For example, when retrieving the
data for a documentary unit, it's repository node is automatically
included in the
relationships
data - however only the mandatory properties for the repository (it'sidentifier
and it's description'sname
andlanguageCode
s) are included in order to reduce unnecessary data transfer. We can, however, force tree serialization to include certain properties (which will apply indiscriminately to all data types thus serialized.) These can be specified in theincludeProps
parameter to the serializer, which takes a list of (string) property names to include in the output. From the REST interface, this can be done with the_ip=<propname>
parameter (which can be given multiple times.)