Anno4j is an Java RDF library to easily cope with annotations conform to the W3C Web Annotation Data Model /W3C Open Annotation Data Model. The library was launched during the MICO Hackathon @ Salzburg May 2015 and will be continuously  developed as open source project in future. It provides an extensible way of creating annotations and is bundled with different body and target implementations which are conform to the standards. Annotations are automatically persisted on local or remote connected SPARQL (SPARQL Protocol and RDF Query Language) endpoints without having to issue any kind of SPARQL query. Besides the creation of annotations, Anno4j also provides an easy-to-use query API based on the path query language LDPath.

The Web Annotation Data Model / Open Annotation Data Model specification describes a structured model and format to enable (web) annotations to be shared and reused across different hardware and software platform. The model is based on RDF (Resource Description Framework), a standard model for data interchange on the Web.

Features

  • Extensible creation of Web/Open Annotations based on Java Annotations syntax.
  • Built-in and predefined implementations for Body and Targets conform to W3C Web Annotation Data Model and W3C Open Annotation Data Model
  • Annotations are transformed to RDF and automatically transmitted to local/remote SPARQL using SPARQL Update functionality
  • Querying of annotations with path-based criteria
    • Basic Comparisons like (equal, greater and lower)
    • Union of different paths
    • Type condition
    • Ordering of results
    • Custom filters

Example: Create and persist annotations

Anno4j uses AliBaba to provide an easy way to extend the W3C Open Annotation Data Model by simply annotating Plain Old Java Objects (POJOs) with the @IRI Java annotation:

// define the rdf:type of the instances of this class
// e.g. <http://example.org/exampleAnnotation> rdf:type oa:Annotation
@Iri(OADM.ANNOTATION)
public class Annotation implements RDFObject {
    
    // define the predicate which connects the annotation with the body instance
    // e.g. <http://example.org/exampleAnnotation> oa:hasBody <http://example.org/exampleBody>   
    @Iri(OADM.HAS_BODY) 
    private Body body;
}

After annotating all needed attributes, the given object can be persisted using Anno4j with a simple persistAnnotation method call:

    // Simple Annotation object
    Annotation annotation = new Annotation();
    annotation.setSerializedAt("07.05.2015");

     // persist annotation
     Anno4j.getInstance().createPersistenceService().persistAnnotation(annotation);

This would lead to the persistence of the annotation object and all of its annotated attributes to the preset repository. Custom annotation bodies or selectors can be easily created and several implementations are already bundled with Anno4j.

Exmaple: Query for annotations

Anno4j also allows to query triple stores without writing own SPARQL queries. Therefore it provides hibernate like criteria queries to query against a particular class and automatically transforms it to valid SPARQL 1.1 queries. Anno4j has a so-called fluent interface, that allows method chaining and therefore helps the user to write readable code.

Keeping the Open Annotation Data Model in mind, an annotation object contains two other objects: the body and the target. The query service provides own methods to directly specify criteria on the respective node. To add a criteria to the annotation body, the setBodyCriteria function has to be invoked.

To add criteria the given setter needs at first a string value representing the LDPath. LD Path is a simple path-based query language similar to XPath or SPARQL Property Paths that is particularly well-suited for querying and retrieving resources from the Linked Data Cloud by following RDF links between resources and servers. For example, the following path query would select the names of all friends of the context resource:

foaf:knows / foaf:name :: xsd:string

A LDPath subset can be directly used in Anno4j to specify your constraint needs. Anno4j supports all common comparison methods like:

  • Equal (Comparison.EQ)
  • Greater than (Comparison.GT)
  • Greater than or else (Comparison.GTE)
  • Lower than (Comparison.LT)
  • Lower than or else (Comparison.LTE)
QueryService<Annotation> queryService = Anno4j.getInstance().createQueryService(Annotation.class);

// search for bodies with rdf:value equal to "Example Value" and the bodies should have a Open Annotation Tag type. 
List<Annotations> result = queryService
    .setBodyCriteria("rdf:value", "Example Value", Comparison.EQ)
    .setBodyCriteria("rdf:type", "oa:Tag")
    .execute();

After adding one or multiple criteria the QueryService can be executed. This means, that the QueryService will automatically create a SPARQL query according to the users namespaces and criteria and use this query to retrieve the data from the triple store and map it back to annotated Java Objects. To achieve this, the execute method has to be invoked.

This is just a short introduction of Anno4j and its features. For more information and a detailed example please visit https://github.com/anno4j/anno4j.