Skip to content

Adapters

Adapters build the model that generators render. Before a generator writes anything it runs a pipeline of adapters: one loads the ontology file, the next fetches imported vocabularies, the next runs a reasoner, and so on until there is a complete set of classes, properties, cardinalities and concepts in memory. Nothing about the ontology reaches a generator except through this pipeline.

You control the pipeline in two places:

  • adapters.<name>.enabled turns an adapter off globally.
  • generators.<name>.adapters restricts one generator to a subset.

What an adapter is

An adapter is a class extending AbstractAdapter<T extends AbstractInfo> with a single method:

java
public abstract T adapt(T info);

There are two AbstractInfo types in play, and both are shared across the whole run:

Info objectBuilt fromHolds
OntologyInfoontology.ontology-file-pathThe Jena model, the inferred model, external ontologies, and the extracted ClassInfo / PropertyInfo tree
ConceptSchemeInfoontology.concepts-file-pathThe concept-scheme model and the extracted class and property concepts

Each adapter declares which type it handles through its constructor, and canAdapt checks the instance before adapt is called. Adapters mutate the object they receive rather than returning a copy, so the pipeline is a chain of in-place enrichments: ontology-load puts a model on OntologyInfo, ontology-class-extract reads that model and adds classes, ontology-property-extract reads those classes and adds properties, and so on. An adapter that runs too early simply finds nothing to work with.

The pipeline

Adapters do not run in the order you declare them. Each adapter carries an @AdapterDependency annotation listing the adapters it needs, and AdapterDependencyComparator sorts the list before every run: an adapter always follows everything it transitively depends on, and adapters at the same dependency depth are ordered by class name. This is the resulting order.

1. concept-scheme-load

Reads the file at ontology.concepts-file-path into a Jena model and puts it on ConceptSchemeInfo. Handles ConceptSchemeInfo; does nothing to the ontology.

2. ontology-load

Reads the file at ontology.ontology-file-path into a Jena model and puts it on OntologyInfo. Every other ontology adapter depends on this, directly or transitively.

3. concept-scheme-extract

Lists every skos:Concept in the concept-scheme model. Concepts carrying owl:equivalentClass become class concepts; concepts carrying owl:equivalentProperty — or an owl:equivalentClass that points at a property URI — become property concepts. Both lists are stored on ConceptSchemeInfo.

4. ontology-extract-external

Collects every owl:imports statement in the ontology model and fetches each referenced vocabulary over HTTP, trying configured mirrors when the original URI fails. Results are parsed into models and registered as external ontologies on OntologyInfo, and cached on disk so later runs do not re-download them. See adapters.ontology-extract-external.

5. ontology-reasoner

Builds a union view of the base model and every fetched external model, runs a Jena reasoner over it, and stores the result as the inferred model on OntologyInfo. Downstream adapters prefer the inferred model when it exists, which is what makes inherited superclasses, inverse properties and imported restrictions visible. The inferred model can be cached on disk and optionally dumped to a file. See adapters.ontology-reasoner.

6. ontology-class-extract

Lists every resource typed owl:Class and turns it into a ClassInfo, then walks rdfs:subClassOf to add superclasses — reading the inferred model when the reasoner ran, the base model otherwise. owl:Restriction nodes are skipped, since they are constraints rather than superclasses. Superclasses in a different namespace than the subclass are marked as external scope, which is how generators later tell your own classes apart from imported ones.

7. concept-class-extract

For every class concept that has no matching class in the ontology yet, creates a ClassInfo for the concept's equivalent class URI, attaches the properties whose rdfs:domain is that class, and then drops any of those properties that has no matching property concept. This is what pulls concept-scheme-only classes into the generated model.

8. ontology-individuals-extract

For each extracted class, lists the resources declared with rdf:type <class> in the ontology model and records them as that class's individuals. Generators use these to build enumerations.

9. ontology-property-extra

Adds each entry of ontology.extra-properties as a property on every class that does not already have that URI, carrying over the configured name, comment, range, cardinality and identifier flag. Use it for columns that must exist in the output but are not modelled in the ontology, such as a uri column.

10. ontology-uri-template

For each ontology class that carries a hydra:search property, parses the linked Hydra template — hydra:template plus the hydra:mapping entries with their hydra:variable and hydra:property — into a UriTemplate on the class. The variable-to-property mapping is what ontology-property-extract later uses to decide which properties are identifiers.

11. ontology-property-extract

The main extraction step. For each class it collects properties from two sources: the owl:Restriction nodes on rdfs:subClassOf, and the owl:ObjectProperty / owl:DatatypeProperty declarations. Properties with the same URI are merged, keeping the strongest cardinality bounds and the union of ranges. It then marks the properties named by the class's URI template as identifiers (creating them if absent) and resolves owl:inverseOf for every property.

12. ontology-datatype-override

Rewrites property ranges according to ontology.override-datatypes. Each entry maps one RDF datatype URI to another RDF datatype URI — for example rdfs:Literal to xsd:string. It does not map to SQL or language-specific types; that translation happens inside the generators.

13. ontology-property-override

Applies ontology.override-properties. For each entry it finds every property with the matching URI on any class and replaces the configured fields: name, comment, range (falling back to datatype when range is absent), cardinality and identifier. Fields you leave out are kept as extracted. Running last means these values win over everything the pipeline inferred.

Enabling and disabling adapters

Every adapter is on by default. Turn one off with:

yaml
adapters:
  ontology-individuals-extract:
    enabled: false

The flag is read directly from the configuration file at bootstrap; a disabled adapter is never instantiated, so it also never appears in any generator's list. Disabling an adapter that others depend on removes its effect from the whole run — switching off ontology-reasoner, for example, makes every downstream adapter fall back to the raw model, which is a legitimate way to get a fast run over a self-contained ontology.

Turning off ontology-load or concept-scheme-load leaves the corresponding model null, and the adapters after it will have nothing to read.

Selecting adapters per generator

By default a generator runs every enabled adapter. Add an adapters list to run a subset:

yaml
generators:
  shacl:
    adapters:
      - "ontology-load"
      - "ontology-class-extract"
      - "ontology-property-extract"

The lookup key is the generator name, not the generator's config prefix. Use generators.shacl.adapters, never generators.shacl-generator.adapters:

GeneratorAdapter selection key
classgenerators.class.adapters
sqlgenerators.sql.adapters
shaclgenerators.shacl.adapters
javagenerators.java.adapters
typescriptgenerators.typescript.adapters
bikeshedgenerators.bikeshed.adapters
odcsgenerators.odcs.adapters
data-framegenerators.class.adapters (shared with class; it has no list of its own)
class-diagramnot usable — see below
er-diagramnot usable — see below

Never put adapters under class-diagram or er-diagram

For these two the generator name and the config prefix are the same string, so the same section is also bound to a typed properties class. The configuration binder uses a strict Jackson mapper, so an unknown key throws IllegalArgumentException: Unrecognized field "adapters" and the run aborts before any generator starts. Let these two generators run the full pipeline instead.

An empty or missing list means "all enabled adapters". Names that are unknown or disabled are skipped with a warning, and the subset is still sorted by dependency order, so listing adapters in the wrong order is harmless.

This selection path has no test coverage and no sample configuration exercises it. Check the log line that names each adapter as it runs to confirm you got the pipeline you intended.

adapters.ontology-reasoner

KeyDefaultMeaning
enabledtrueRun the reasoner at all
rules-file""Path to a Jena rules file; when set, a GenericRuleReasoner is built from it and reasoner-type is ignored. If the file fails to load, the configured reasoner type is used instead
reasoner-type"owl"owl (OWL Micro), rdfs (lighter and faster) or transitive. Anything else falls back to OWL Micro
reasoner-materializefalseCall InfModel.prepare() to materialise all inferences up front
reasoner-timeout-ms0Abort reasoning after this many milliseconds; 0 disables the timeout
inferred-cache-enabledtrueCache the inferred model on disk between runs
inferred-cache-ttl-ms3600000Cache entry lifetime in milliseconds; 0 or less means never expire
inferred-cache-dirtarget/cache/inferredDirectory for cached inferred models
inferred-cache-formatTURTLEJena language name used to read and write cache entries
inferred-output-enabledfalseAlso write the inferred model to a file of your choice
inferred-output-path""Destination for that file; only used when inferred-output-enabled is true
yaml
adapters:
  ontology-reasoner:
    enabled: true
    rules-file: "src/test/resources/examples/reasoner.rules"
    reasoner-type: "owl"
    reasoner-materialize: true
    reasoner-timeout-ms: 0
    inferred-cache-enabled: true
    inferred-cache-ttl-ms: 3600000
    inferred-cache-dir: "target/cache/inferred"
    inferred-cache-format: "TURTLE"
    inferred-output-enabled: true
    inferred-output-path: "target/inferred/inferred.ttl"

Reasoning over a large imported vocabulary is the slowest part of a run. Leave the cache on, and switch reasoner-type to rdfs when you do not need OWL inference.

adapters.ontology-extract-external

KeyDefaultMeaning
enabledtrueFollow owl:imports at all
connect-timeout-ms2000HTTP connect timeout
read-timeout-ms5000HTTP read timeout
max-retries1Retries per candidate URI
follow-redirectstrueFollow HTTP redirects
user-agentoddtoolkit/1.0User-Agent header sent with each request
cache-enabledtrueCache downloaded ontologies on disk
cache-ttl-ms3600000Cache entry lifetime in milliseconds; 0 or less means never expire
cache-max-entries100Maximum number of cached entries
cache-dirtarget/cache/ontology-extract-externalCache directory; a blank value disables the file cache
cache-formatTURTLEJena language name used to read and write cache entries
mirrorsemptyAlternative download locations, tried after the original URI

Each mirrors entry has:

KeyMeaning
uriThe imported ontology URI this entry applies to
mirrorsList of alternative locations, tried in order
mirrorSingle alternative location; used only when mirrors is absent

Mirrors matter because many vocabulary URIs do not serve RDF over content negotiation. The original URI is always tried first, then each mirror in turn.

yaml
adapters:
  ontology-extract-external:
    cache-enabled: true
    cache-dir: "target/cache/external"
    cache-ttl-ms: 3600000
    mirrors:
      - uri: "http://www.w3.org/ns/prov#"
        mirrors:
          - "https://www.w3.org/ns/prov-o"
      - uri: "http://xmlns.com/foaf/0.1/"
        mirrors:
          - "https://xmlns.com/foaf/spec/index.rdf"
      - uri: "http://www.w3.org/ns/adms#"
        mirror: "https://www.w3.org/ns/legacy_adms.ttl"

If you work offline, set enabled: false and make sure your ontology file is self-contained.

Other adapters

The remaining eleven adapters take no configuration of their own beyond enabled. They read ontology.*extra-properties, override-properties, override-datatypes and the rest — which is documented in the Configuration Reference.

See also

Released under the GNU General Public License v3.0.