annotations library

Annotation library for mapping Dart classes to RDF graphs.

This library provides a set of annotations that can be applied to Dart classes and properties to declare how they should be mapped to and from RDF graphs. Used in conjunction with the locorda_rdf_mapper_generator package, these annotations enable automatic generation of mapper implementations without writing boilerplate code.

Core RDF mapping concepts:

  • Resource: An entity in the RDF graph, which can be identified by an IRI (global) or represented as a blank node (local)
  • Property: A relation between a resource and a value (another resource or a literal)
  • IRI (Internationalized Resource Identifier): A unique identifier for a resource
  • Blank Node: An anonymous resource without a global identifier
  • Literal: A simple value like a string, number, or date

Integration with locorda_rdf_mapper: You don't need to use annotations for all your classes. You can freely mix and match:

  • Annotated classes with automatically generated mappers
  • Custom mapper implementations registered directly with locorda_rdf_mapper

This flexibility allows you to use annotations for standard cases while implementing custom mappers for more complex scenarios. Custom mappers can be registered either:

  • Globally after calling initRdfMapper
  • Locally for specific operations via the register parameter in mapper methods

Example using annotations (recommended for most cases):

import 'package:locorda_rdf_mapper_annotations/annotations.dart';
import 'package:locorda_rdf_terms_common/foaf.dart'; // Contains RDF vocabulary terms

// Define your class with annotations
@RdfGlobalResource(FoafPerson.classIri, IriStrategy('http://example.org/people/{id}'))
class Person {
  @RdfIriPart('id')
  final String id;

  @RdfProperty(FoafPerson.name)
  final String name;

  @RdfProperty(FoafPerson.age)
  final int age;

  Person({required this.id, required this.name, required this.age});
}

// The initRdfMapper function is automatically generated, lets use it to get an rdfMapper facade.
final rdfMapper = initRdfMapper();
final personTurtle = rdfMapper.encodeObject(person);
final decodedPerson = rdfMapper.decodeObject<Person>(personTurtle);

Example of manually implementing and registering a mapper:

// Manual mapper implementation
class PersonMapper implements GlobalResourceMapper<Person> {
  @override
  (IriTerm, List<Triple>) toRdfResource(Person instance, SerializationContext context, {RdfSubject? parentSubject}) {
    return context.resourceBuilder(context.createIriTerm(instance.id))
      .addValue(FoafPerson.name, instance.name)
      .build();
  }

  @override
  Person fromRdfResource(IriTerm subject, DeserializationContext context) {
    return Person(
      id: subject.value,
      name: context.reader.require<String>(FoafPerson.name),
    );
  }

  @override
  IriTerm get typeIri => FoafPerson.classIri;
}

// Register globally after initRdfMapper:
final rdfMapper = initRdfMapper(); // From generated code
rdfMapper.registerMapper<Person>(PersonMapper());

// Or register for a specific operation:
final turtle = rdfMapper.encodeObject(
  person,
  register: (registry) => registry.registerMapper<Person>(PersonMapper()),
);

You can also combine both approaches, using annotations for most classes and manual mappers for special cases:

// For a class with annotations, the mapper is generated automatically
@RdfGlobalResource(FoafPerson.classIri, IriStrategy('http://example.org/people/{id}'))
class Person {
  // Properties with annotations...
}

// For a complex class, implement a custom mapper
class CustomEventMapper implements GlobalResourceMapper<Event> {
  // Custom implementation...
}

// Use both in your application
final rdfMapper = initRdfMapper();
rdfMapper.registerMapper<Event>(CustomEventMapper());

// Both mappers are now available
final person = rdfMapper.decodeObject<Person>(personTurtle);
final event = rdfMapper.decodeObject<Event>(eventTurtle);

The primary annotations are organized into two categories:

Class-level annotations define how a class is mapped to RDF nodes:

Property-level annotations define how properties are mapped:

  • RdfProperty: Main property annotation, links to an RDF predicate
  • RdfIriPart: Marks properties that contribute to IRI construction
  • RdfValue: Identifies the value source for literal serialization
  • RdfMapEntry: Specifies how map entries shall be (de-)serialized

Enum-specific annotations customize enum serialization:

  • RdfEnumValue: Customizes individual enum constant serialization values

Enum Support

The library provides comprehensive support for mapping enums to RDF values:

// Literal enum mapping
@RdfLiteral()
enum Priority {
  @RdfEnumValue('H')
  high,     // → "H"
  medium,   // → "medium"
}

// IRI enum mapping
@RdfIri('http://example.org/status/{value}')
enum Status {
  @RdfEnumValue('active-state')
  active,   // → <http://example.org/status/active-state>
  pending,  // → <http://example.org/status/pending>
}

// Usage in resource classes
@RdfGlobalResource(...)
class Task {
  @RdfProperty('http://example.org/priority')
  final Priority priority; // Uses enum's default mapping

  @RdfProperty(
    'http://example.org/status',
    literal: LiteralMapping.namedMapper('customStatusMapper')
  )
  final Status status; // Override with custom mapper
}

Enums can be annotated with either @RdfLiteral or @RdfIri to define their default mapping behavior. Individual enum constants can use @RdfEnumValue to override their serialization value. This enables clean Dart enum names while supporting domain-specific RDF vocabularies.

For usage examples, see the example directory.

Classes

BaseMapping<M>
Base class for all mapping configurations that share common mapper functionality.
BaseMappingAnnotation<M extends Mapper>
CollectionMapping
Configures mapping details for collection properties in RDF.
ContextualMapping
Configuration for contextual property mapping.
GlobalResourceMapping
Configures mapping details for global resources (resources with IRIs) at the property level.
IriMapping
Configures mapping details for IRI terms in RDF at the property level.
IriStrategy
Defines the strategy for generating IRIs for RDF resources.
LiteralContent
Represents the content for building an RDF Literal.
LiteralMapping
Configures mapping details for literal values in RDF at the property level.
LocalResourceMapping
Configures mapping details for local resources (blank nodes) at the property level.
MapperRef<M>
Base class for type-safe mapper references.
RdfAnnotation
Base annotation interface for RDF mapper generation.
RdfEnumValue
Annotation for customizing how individual enum constants are serialized in RDF.
RdfGlobalResource
Marks a Dart class as an RDF resource with a global IRI.
RdfIri
Marks a Dart class or enum as representing an RDF IRI term.
RdfIriPart
Marks a property as a part of the IRI for the enclosing class.
RdfLanguageTag
Marks a property as providing the language tag for RDF literals.
RdfLiteral
Marks a Dart class or enum as representing an RDF literal term.
RdfLocalResource
Marks a Dart class as a local RDF resource (referred to via a blank node).
RdfMapEntry
Specifies the Dart Type that represents each entry in a Map.
RdfMapKey
Designates a property as the key in a mapped Map<K,V> collection.
RdfMapValue
Designates a property or class as the value in a mapped Map<K,V> collection.
RdfProperty
Maps a Dart class property to an RDF predicate.
RdfProvides
Marks a property as providing a named value that can be referenced in IRI templates in the RDF mapping system.
RdfUnmappedTriples
Marks a property to capture and preserve unmapped RDF triples during lossless mapping.
RdfValue
Marks a property within a class as the primary value source for RDF literal conversion.

Enums

MapperDirection
Specifies whether a mapper should handle serialization, deserialization, or both.

Constants

rdfAlt → const CollectionMapping
Maps Dart collections to RDF Alternative structures (first is preferred).
rdfBag → const CollectionMapping
Maps Dart collections to RDF Bag structures (unordered collections).
rdfList → const CollectionMapping
Maps Dart collections to RDF List structures (rdf:first/rdf:rest/rdf:nil).
rdfSeq → const CollectionMapping
Maps Dart collections to RDF Sequence structures (rdf:_1, rdf:_2, rdf:_3...).
unorderedItems → const CollectionMapping
Maps Dart Iterable collections to multiple separate triples.
unorderedItemsList → const CollectionMapping
Maps Dart List collections to multiple separate triples.
unorderedItemsSet → const CollectionMapping
Maps Dart Set collections to multiple separate triples.