Skip to content
Martin Ledvinka edited this page Jun 27, 2023 · 3 revisions

Descriptors are used in JOPA to parameterize entity operations. They form a simple hierarchy of descriptors shown in the following image.

descriptors

  • EntityDescriptor is the root describing an entity. If an entity references another entity (via object or annotation property), another EntityDescriptor can be used to describe the attribute
  • ObjectPropertyCollectionDescriptor is used to describe a plural object property attribute. It references an EntityDescriptor that is used to describe the elements
  • FieldDescriptor is used to describe a literal value attribute (datatype or annotation property)

Descriptors work recursively. So unless a setting is overridden in another descriptor, the value from the root descriptor applies. Also, a descriptor can be set as an attribute descriptor of itself. This can be handy for recursive structures like composites.

The following sections provide details of what can be configured with descriptors.

RDF Named Graphs (Contexts)

RDF named graphs (called contexts in JOPA API) allow to partition the storage into logical, uniquely identified collections of data.

Descriptors can specify the contexts (named graphs) of the relevant entity and (optionally) customize the contexts used for its attributes or referenced entities.

An EntityDescriptor can specify the context in which an entity is stored together with its attributes. Unless customized, all attributes of an entity are stored in the same context as the descriptor subject.

When configuring attributes, one has two options. It is possible to set just the attribute context via the addAttributeContext method. The descriptor will decide whether another EntityDescriptor or a FieldDescriptor will be used based on the attribute type. Object properties get a new EntityDescriptor, data and annotation properties get a FieldDescriptor. Another option is to call addAttributeDescriptor to specify the descriptor directly. In case of literal values, the property assertion is stored in the target context. In case of object properties, the property assertion is stored in the subject's context by default. This can be overridden by passing a false parameter to one of the EntityDescriptor constructors, which means that property assertions are stored in the target object's context.

For example, consider entities a and b.

a.hasB = b;
EntityDescriptor desc = new EntityDescriptor(URI.create("http://contextOne"));
desc.addAttributeDescriptor(hasBAttribute, new EntityDescriptor(URI.create("http://contextTwo"));
entityManager.persist(a, desc);

This will in effect lead to the following quads:

:a a :A http://contextOne .
:a :hasB :b http://contextOne .
:b a :B http://contextTwo .

In contrast, if we have the following code:

a.hasB = b;
EntityDescriptor desc = new EntityDescriptor(URI.create("http://contextOne"), false);
desc.addAttributeDescriptor(hasBField, new EntityDescriptor(URI.create("http://contextTwo"));
entityManager.persist(a, desc);

Then, the following quads will be the result:

:a a :A http://contextOne .
:a :hasB :b http://contextTwo .
:b a :B http://contextTwo .

Notice where the property assertion is stored this time - in the context of the target entity.

Plural Contexts

It is possible to specify multiple contexts for a descriptor or any of its attributes. However, this can be used only for retrieval operations, where a union of these contexts is used to get data. This can be useful when data are stored in a set of named graphs and the application does not know concrete context for a particular entity, but it cannot use the default context to prevent data conflicts. For write operations (persist, update), at most one context can be specified. If multiple are encountered, an AmbiguousContextException is thrown.

Language

Descriptors can also be used to override the persistence unit-wide language configuration (cz.cvut.jopa.lang). This allows configuration of string-valued attributes loading and saving. Once again, setting the value on a root descriptor applies to all descriptors it references unless overridden.

Let's say we have the persistence unit configured to use English as the default string language (quite common setting). Suppose we have an entity class describing historical monuments and the following data about Wenceslas Square in Prague (in Turtle syntax):

<https://dbpedia.org/page/Wenceslas_Square> a <http://dbpedia.org/ontology/Place> ;
  rdfs:label "Wenceslas Square"@en , "Václavské náměstí"@cs .

Now, creating a descriptor and setting its language to Czech (or even just the label attribute) will ensure that JOPA will load the instance with the Czech label in this case

Descriptor d = new EntityDescriptor().setLanguage("cs");
Monument wSquare = em.find(Monument.class, URI.create("https://dbpedia.org/page/Wenceslas_Square"), d);
assert wSquare.getLabel() == "Václavské náměstí";

Inference

On more feature that can be configured via descriptors is inference. More specifically, if an attribute is marked as potentially containing inferred values (via the @Inferred annotation), a descriptor can be used to disable loading inferred values for the attribute.

Descriptor d = new EntityDescriptor().disableInference();
Monument wSquare = em.find(Monument.class, URI.create("https://dbpedia.org/page/Wenceslas_Square"), d);

The instance will be loaded with asserted data only.