Anno4j is an Java RDF library to easily cope with annotations conform to the W3C Web Annotation Data Model/W3C Open Annotation Data Model. Since the first version of Anno4j was  released during the MICO Hackathon at Salzburg May 2015, the library was continuously improved by the MICO team. By the end of year 2015 we finally released a major update with Anno4j v2.0, which includes querying features, a redesign of the internal architecture and a plugin mechanism for third party integrations like for example SPARQL MM.

Major Changes in  Anno4j v2.0

During the development of Anno4j we got a lot of input from project partners as well as from external developers who are using Anno4j. This experiences helped us immensely in our design decisions for version 2.0. At first we removed the singleton design pattern for the Anno4j object. In v2.0 it is possible to create multiple instances of this object and therefore one project can use different triple stores to store their data.

Another major change was the usage of interfaces instead of classes for bodies, selectors and targets. This reduces the effort massively when defining custom nodes, because the user only has to define and annotate the getter and setter for the interfaces and on the other sides allows the definition of multiple rdf:type relationships for instances. Custom behaviour for instances can now be implemented with abstract classes and the @Partial annotation.

With version 2, we also removed the shortcut functions (i.e.the setBodyCriteria or the setTargetCriteria method) of the QueryService. Every path has to start now from the Annotation node and therefore the user now should only use the addCriteria function to define path exrpessions. The reason for that change was, that we want the users to understand the underlying model and therefore it is necessary to write the complete path by themselves.

The last noteable change of v2 was the implementation of a straightforward extensibilty mechanism for evaluating predefined or custom path expressions. Developers are now able to define own path expressions and the related evaluators using the @Evaluator Java annotation. The new generated LDPath syntax will be automatically registered in the system and therefore can be used to define new LDPath expressions with custom behaviour.

Supported LDPath syntax

Besides changes made, mentioned above, we also extended the QueryService by new LDPath language expressions. The following section shows a complete list of all supported expressions of Anno4j v2.0:

Property Selections

A path definition selecting the value of a property. Either a URI enclosed in <> or a namespace prefix and a local name separated by :


Select the foaf:name property using namespace prefix and local name:

"foaf:name" | "<>"

Reverse Property Selections

This is the reverse/inverse operation of the normal Property Selection. Select all nodes connected to the current node via an incoming link, aka. go the specified link “backwards”:


Get the names of all persons that link the current person as foaf:knows:

 "^foaf:knows / foaf:name"

Path Traversal

Traverse a path by following several edges in the RDF graph. Each step is separated by a /: `PATH / PATH`. Where PATH is an arbitrary path selector (e.g. a property selection or test).


Traverse a path by following several edges in the RDF graph. Each step is separated by a /.



Several alternative paths can be merged by using a union | between path elements: `PATH | PATH`. Where PATH is an arbitrary path selector.


Select the labels or names of all friends:

"foaf:knows/foaf:name | foaf:knows/rdfs:label"


The intersection of several paths can be computed by using an intersection & between path elements: `PATH & PATH`. Where PATH is an arbitrary path selector.


Select values that are both defined for foaf:interest and foaf:topic_interest:

"foaf:interest & foaf:topic_interest"

Recursive Selections

Recurseive selection will apply an selectore recursively. Anno4j supports the zero-and-more(`(<SELECTOR>)*`) and the one-and-more(`(<SELECTOR>)+`) selectors.


Path expressions can be grouped to change precedence or to improve readability by including them in braces: `( PATH )`, where PATH is an arbitrary path selector.


Select the labes or names of friends:

"foaf:knows/(foaf:name | rdfs:label)"

Value Testing

The values of selections can be tested and filtered by adding test conditions in square brackets [] after a path selection: `PATH [TEST]`, where PATH is an arbitrary path selector and TEST is a test condition (see below).

Literal Language Test

Literal language tests allow to select literal values of only the specified language. They can be expressed by @ followed by the ISO language tag or the special value none to select literals without language definition: `@LANGUAGE`, where LANGUAGE is the ISO language tag.


Select labels with either German language:


Literal Type Test

Literal type tests allow to select only literals of a specified type, e.g. to ensure that only decimal values are indexed: `^^TYPE`, where TYPE is the XML Schema type to select.


Select all literal values of type xsd:decimal:


Resource Path Value Tests

Resource path value tests only allow resources where a subpath selection matches a certain value condition: `PATH is VALUE`, where PATH is an arbitrary path selection and VALUE is a URI, prefix:local, or literal value definition.


Select all interests of type ex:Food (path condition):

"foaf:interest[rdf:type is ex:Food]"

Test Conjunction and Disjunction

Several tests can be connected using & (for conjunction/and) or | (for disjunction/or).


Select all interests of type ex:Food or type ex:Drink:

"foaf:interest[rdf:type is ex:Food | rdf:type is ex:Drink]"

Select all interests of type ex:Food and type ex:Drink:

"foaf:interest[rdf:type is ex:Food & rdf:type is ex:Drink]"

Combinations of Tests

A path traversal can contain several tests.


Select the spanish label of all interests of type ex:Food

"foaf:interest[rdf:type is ex:Food]/rdfs:label[@es]"

Anno4j is open source and not tailored to a specific MICO use case. You can use it for generic Web Annotations implementations in your project and integrate your custom plugins. We are happy if you contribute to the project or help us to improve the software.