-
Notifications
You must be signed in to change notification settings - Fork 15
Object ontological Mapping
Object-ontological mapping (OOM) in JOPA is, much like in JPA, realized via annotations in Java.
The annotations tell JOPA which classes it should consider as entity classes, which of their attributes are persistent and to what ontological properties they are mapped.
The most important annotations in this regard are:
@OWLClass
is placed on a Java class and specifies that this class is a part of the persistence unit metamodel. It has one attribute - iri
- whose value maps the class to the corresponding RDFS/OWL class.
@Id
marks field which contains the instance's identifier (IRI in ontological terms). Supported types are String
, java.net.URI
and java.net.URL
.
The identifier can be marked as generated
, so that when an instance with an empty identifier is persisted, JOPA will generate the identifier value. The generated identifier is generally based on the entity class IRI, with some random data appended to it.
@OWLObjectProperty
marks Java attributes which reference other objects. In OWL, this corresponds to object properties, which link individuals to other individuals. RDF makes no such distinction.
However, for JOPA, the distinction between @OWLObjectProperty
and other kinds of properties (see below) is important. They tell it whether it should expect a literal value (like an integer, String) or a resource's identifier. Therefore, when using RDF-based storage like RDF4J, @OWLObjectProperty
should still be used, marking fields whose type is either another entity class or String
/java.net.URI
/java.net.URL
. In case the type is String
/URI
/URL
, JOPA will assume that the intended value is an individual's identifier (this is referred to as plain identifier object property in Javadoc and source code. No other types can be used for fields annotated with @OWLObjectProperty
.
The iri
attribute represents the property to which the annotated attribute is mapped.
fetch
specifies whether the attribute value should be eagerly or lazily loaded (it is supposed to work the same as in JPA). Note that when using data access objects, it is usually better to have the fetch
set to eager. Since JOPA currently does not support extended persistence contexts, once the loaded object becomes detached from the persistence context (usually when returned from DAO/service with transactional entity manager), lazily loaded attributes may be null
without any way to load them. Defaults to FetchType.LAZY
.
cascade
whether entity manager operations should be cascaded over this attribute. This works the same way as in cascading in JPA.
@OWLDataProperty
marks a literal-valued field. This corresponds to an OWL datatype property. Again, RDF does not care about this distinction, but JOPA will assume the value to be a literal and treat it as such. The annotated fields should not used Java primitive types but their wrapper equivalents, i.e. Integer
for int
etc.
The iri
attribute represents the property to which the annotated attribute is mapped.
fetch
works same as above. It defaults to FetchType.EAGER
for data properties.
lexicalForm
allows to load the property value into a String
regardless of the type of the literal. This functionality, however, has a limitation - such an attribute would be read-only. This is because when the field is a String representing lexical form of the literal, JOPA has no way of knowing what the type of the literal should be when saving it (e.g., on persist, or even on update). Updating could thus lead to unintentional changes in the data. A safer way is thus to prevent modification of such values.
simpleLiteral
configures the property to be stored/accessed as a RDF simple literal, i.e. a literal stored as xsd:string
. Simple literals allow to store string literals without worrying about language tags. Note that language tagged strings can be loaded as simple literals. However, any changes to them will be stored as simple literals, so language information will be lost in that case.
@OWLAnnotationProperty
correspond to OWL annotation properties. The notion is not known in RDF, so when accessing RDF-based storages, this annotation can be ignored and OWLDataProperty
used instead. However, when using OWL-based storage (i.e. currently only OWL API), the distinctions between different kinds of properties are significant.
The iri
attribute represents the property to which the annotated attribute is mapped.
fetch
works same as above. It defaults to FetchType.EAGER
for annotation properties.
lexicalForm
works the same way as above. If the annotation value is an resource/individual, its identifier is loaded into the attribute. The read-only conditions, however, applies to it as well.
simpleLiteral
works the same way as in data properties (see above). If the annotation value is an resource/individual, its identifier is loaded into the attribute.
Below is a simple example of a JOPA entity, which makes use of all the aforementioned kinds of properties:
@OWLClass(iri = Vocabulary.s_c_Occurrence)
public class Occurrence {
@Id
private URI uri;
@OWLDataProperty(iri = Vocabulary.s_p_has_key)
private String key;
@OWLAnnotationProperty(iri = CommonVocabulary.RDFS_LABEL)
private String name;
OWLObjectProperty(iri = Vocabulary.s_p_has_part, fetch = FetchType.EAGER, cascade = {CascadeType.MERGE,
CascadeType.REMOVE})
private Set<Event> children;
// Getters and setters follow
}
If a field should not persistent, one of the following mechanisms can be used:
- Field is
static
- Field is
transient
- Field is annotated with
@Transient
In RDF (and OWL), everything is a set - an RDF graph is a set of statements, multiple values of a property represent a set, i.e., there are not duplicates and there is no particular order. This is reflected by JOPA in that plural attributes are by default mapped to a java.util.Set
. If the field type is java.util.Collection
, the implementation used by JOPA will also by a set (typically a java.util.HashSet
).
Lists, i.e., ordered sequences of statements, are supported by multiple additional features:
- OWL sequences
- RDF collections
- RDF containers
OWL sequences represent an implementation of an ontology design pattern. There are two types of sequences:
- Simple
- Referenced
A simple list is basically a linked list of resources that each point to the next in the sequence. As such, they do not support literals. Referenced lists consist of list nodes that each point to a value (which can be a resource or a literal) and to the next node in the list. Reference list nodes are generated automatically by JOPA. The following snippet shows definition of attributes of both kinds:
@Sequence(type = SequenceType.referenced) // This is the default sequence type
@OWLObjectProperty(iri = "http://example.com/referencedList")
private List<Integer> marks;
@Sequence(type = SequenceType.simple)
@OWLObjectProperty(iri = "http://example.com/simpleList")
private List<URI> isolationLevels;
RDF Collections, more specifically RDF lists work the same way as referenced sequences discussed above. The only difference is that RDF Lists use a controlled vocabulary and the list itself is terminated by a rdf:nil
node (referenced sequence does not have a distinct terminal node). They can be used as follows:
@RDFCollection
@OWLObjectProperty(iri = "http://example.com/rdfCollection")
private List<URI> isolationLevels;
RDF Containers define vocabulary and an informal semantics description (it is not enforced by the standard, though) for three types of containers - alternatives, bags, and sequences. The RDF Schema specification implies that an rdf:Alt
is a set of distinct alternative values, a rdf:Bag
is an unordered container, and a rdf:Seq
is an ordered sequence of values.
JOPA enforces some basic rules based on the informal description of the meaning of the various containers:
- A
rdf:Seq
cannot be mapped tojava.util.Set
- A
rdf:Alt
cannot be mapped tojava.util.List
RDF containers can store both individuals and literals.
The mapping can be used for example as follows:
@RDFContainer(type = RDFContainerType.SEQ)
@OWLObjectProperty(iri = "http://example.com/rdfContainer")
private List<URI> isolationLevels;