tomato·bazeldocs v0 · latest
Docs/Reference/Modules/rules_jena

rules_jena

Apache Jena toolchain implementations for rules_rdf — SPARQL engine (ARQ), SHACL validator, Turtle/N-Triples serializers, OWL reasoner. Java tools built via rules_java + Maven.

Latest0.3.2
Versions8
CategoryBazel rules
MaintainersMatt Marshall
Registryhttps://registry.tbzl.dev/modules/rules_jena/
Sourcegithub.com/tomato-bazel/rules_jena
MODULE.bazelstarlark
bazel_dep(name = "rules_jena", version = "0.3.2")

View source & releases on GitHub ↗

Apache Jena toolchain implementations for rules_rdf — SPARQL engine (ARQ), SHACL validator, Turtle/N-Triples serializers, OWL reasoner. Java tools built via rules_java + Maven (pinned through rules_jvm_external).

rules_jena is the analog for rules_rdf that rules_openapi is for rules_jsonschema: a concrete, language-specific implementation satisfying an abstract toolchain contract. The contract lives in rules_rdf; the binaries that fulfil it live here.

Status: v0.2.0

What v0.2 adds on top of v0.1.1:

  • Bazel-idiomatic Jena data primitives (provider-only) — jena_model, jena_dataset, jena_rule_set, jena_reasoner. See docs/model.md, docs/dataset.md, docs/rules.md, docs/reasoner.md. Every model + dataset also emits RdfDatasetInfo so they’re drop-in for rules_rdf rules.
  • Three new java_binaries satisfying every remaining rules_rdf toolchain type: jena_shacl (rdf_validator), jena_riot (rdf_serializer), jena_reasoner_bin (rdf_reasoner). All pass the rules_rdf conformance driver.
  • Auto-registered toolchains for all four — pulling in rules_jena now provides a complete rules_rdf backend.
  • End-to-end SHACL gate smoke (examples/validate/people_conform) runs through the chain jena_modelrdf_validate_testjena_shacl toolchain.

Deferred to v0.3 (see docs/ROADMAP.md):

  • jena_reason build action (today’s rdf_reason test rule lives in rules_rdf v0.2’s roadmap; until then, datasets + reasoners are provider-ready but the build-action consumer needs rules_rdf v0.2).
  • jena_fuseki HTTP-server dev runner.
  • Port Loader.java + deterministic Writer.java from the Aion kg/java/ corpus as a public :jena_io java_library.
  • Severity-aware SHACL filtering (today --severity is accepted but coarsely interpreted).

v0.1.1 status (still shipped):

What ships:

  • @jena_maven — Apache Jena 5.2.0 + slf4j-simple 2.0.16, pinned via rules_jvm_external with a committed maven_install.json. Same artifact set as the production kg/java/ JENA_DEPS constant.
  • JENA_DEPS (from @rules_jena//jena:defs.bzl) — the five Maven labels every Jena-using java_binary needs, exposed as a publicly re-exportable Starlark constant. Downstream consumers load("@rules_jena//jena:defs.bzl", "JENA_DEPS") and spread it into their deps attr instead of hand-rolling their own list. Stardoc reference in docs/defs.md.
  • //jena/sparql:jena_sparqljava_binary implementing rules_rdf’s sparql_engine_toolchain_type plugin contract. Reads RDF from stdin, executes a SPARQL query from --query=<path>, emits results (TSV / CSV / JSON / SRX for SELECT, Turtle for CONSTRUCT/DESCRIBE) to stdout. SELECT + ASK
    • CONSTRUCT + DESCRIBE all supported. --fail-on-nonempty drives the zero-row gate idiom.
  • //jena:jena_sparql_toolchain_def — toolchain registration. Auto-registered in MODULE.bazel so consumers don’t have to.
  • Conformance test (//jena:jena_sparql_conforms) — runs rules_rdf’s rdf_plugin_contract_test driver against the binary. All four scenarios pass: valid_minimal, malformed_input, unknown_flag, determinism.
  • End-to-end smoke (examples/smoke/) — a FOAF dataset + a SPARQL zero-row gate, resolved through the registered toolchain. bazel test //examples/smoke:all passes.

Deferred to v0.2 (see docs/ROADMAP.md):

  • SHACL validator (jena_shacl) → rdf_validator_toolchain_type.
  • RIOT format converter (jena_riot) → rdf_serializer_toolchain_type.
  • OWL reasoner (jena_reasoner) → rdf_reasoner_toolchain_type.
  • Port Loader.java + Writer.java from ~/Documents/rfcs/kg/java/ as public //jena:loader + //jena:writer java_library targets.

Planned implementations

Each row binds one rules_rdf toolchain type to a Jena-backed java_binary. All binaries take their input on stdin / argv and emit results on stdout, matching the rules_rdf plugin contract.

rules_rdf toolchain typeJena backingPattern source
sparql_engine_toolchain_typeARQ (org.apache.jena.query.QueryExecutionFactory) — read .rq from argv, .ttl from stdin, results to stdoutgate_query_smoke in kg/java/BUILD.bazel
shacl_validator_toolchain_typeorg.apache.jena.shacl.ShaclValidator — shapes + data graph in, conformance report outgate_shacl / GateShacl.java
rdf_serializer_toolchain_typeJena’s RDFDataMgr + the deterministic Turtle writer patterns from Writer.java (byte-stable round-trip + parse-equivalence)Writer.java + WriterTest.java
owl_reasoner_toolchain_typeReasonerRegistry.getOWLMicroReasoner() — matches what kg_reasoner runs in production todaykg/java/reasoner:kg_reasoner

The shared corpus-loading library (kg.Loader) ports to a public //:rdf_io java_library that every toolchain binary depends on.

Sources of inspiration

The patterns this repo will package as toolchains all already exist in production today, in the Aion RFC knowledge-graph Java tree (~/Documents/rfcs/kg/java/). See docs/SOURCES.md for the per-file catalog of what gets ported and what each source teaches:

  • Loader.java — single-source-of-truth for “load every TTL under a corpus root into one in-memory Dataset”. The shared dependency for every binary that reads RDF.
  • Writer.java — deterministic Turtle serializer with byte-stable round-trip (the property the corresponding test locks down).
  • GateHarness.java + Gates.java — orchestrates SPARQL zero-row gates and SHACL conformance against a Dataset.
  • GateZeroRows.java, GateQuerySmoke.java, GateShacl.java — the three reusable PR-gate shapes.
  • KgReasoner.java (under kg/java/reasoner/) — OWL-MICRO inference over a corpus with Jena rule files.

rules_jena will extract these into reusable, contract-conforming toolchain binaries plus a small public :rdf_io library, deleting the hand-rolled JENA_DEPS lists from downstream consumers.

Install

.bazelrc:

common --registry=https://registry.fastverk.com/
common --registry=https://bcr.bazel.build/

MODULE.bazel:

bazel_dep(name = "rules_jena", version = "0.2.0")

rules_rdf, rules_java, and rules_jvm_external (the Maven artifact pinner) are pulled in transitively once toolchains land in v0.1. The default Jena-backed toolchains will be registered automatically.

Compatibility

  • Bazel: 7.4+, bzlmod required.
  • Java: 17+.
  • Jena: the JENA_DEPS set used by the source corpus today — jena-arq, jena-core, jena-base, jena-iri, plus slf4j-simple for runtime logging. Maven coordinates pinned in v0.2.

License

MIT.

Usage#

Real usage, taken from the module’s examples/.

examples/dataset_library/BUILD.bazel

load("@rules_java//java:defs.bzl", "java_test")
load("@rules_jena//jena:defs.bzl", "jena_dataset_library")

# The fixture graph, bundled into a java_library with a generated
# example.dataset.Fixture.load() accessor.
jena_dataset_library(
    name = "fixture",
    srcs = ["fixture.ttl"],
    package = "example.dataset",
    classname = "Fixture",
)

# Loads it from the classpath and checks the triple count.
java_test(
    name = "load_test",
    srcs = ["LoadTest.java"],
    main_class = "example.dataset.LoadTest",
    use_testrunner = False,
    deps = [
        ":fixture",
        "@jena_maven//:org_apache_jena_jena_core",
    ],
)

examples/reason/BUILD.bazel

load("@rules_jena//jena:defs.bzl", "jena_dataset", "jena_model", "jena_reasoner")

package(default_visibility = ["//visibility:public"])

jena_model(
    name = "ontology",
    srcs = ["ontology.ttl"],
    in_format = "turtle",
)

jena_model(
    name = "facts",
    srcs = ["facts.ttl"],
    in_format = "turtle",
)

# Dataset composing the TBox (ontology) + ABox (facts) — flat
# combined model for the v0.2 reasoner pass.
jena_dataset(
    name = "world",
    default_graph = ":ontology",
    named_graphs = {
        "http://example.org/g/facts": ":facts",
    },
)

# RDFS reasoner — built-in profile, no rule_set needed.
jena_reasoner(
    name = "rdfs",
    profile = "rdfs",
)

# v0.2 ships the providers + the rdf_reasoner_toolchain — the
# user-facing rdf_reason rule that consumes them lands in
# rules_rdf v0.2 (its v0.1 only ships sparql_query_test +
# rdf_validate_test). Until then the smoke is "everything builds
# and provides the right info" — the jena_reasoner_bin binary's
# conformance test is what proves the toolchain is wired right.
filegroup(
    name = "smoke",
    srcs = [":world", ":rdfs"],
)

examples/schemagen/BUILD.bazel

load("@rules_java//java:defs.bzl", "java_test")
load("@rules_jena//jena:defs.bzl", "jena_model", "jena_schemagen")

# A toy ontology to exercise the schemagen rule end-to-end.
jena_model(
    name = "fixture_ttl",
    srcs = ["fixture.ttl"],
    in_format = "turtle",
)

# Generate example.schemagen.Spec from the fixture — gains static
# Resource / Property constants for every term in the ontology.
jena_schemagen(
    name = "fixture_vocab",
    classname = "Spec",
    dataset = ":fixture_ttl",
    namespace = "https://example.org/spec#",
    package = "example.schemagen",
)

# Compile-time + runtime check: the generated Spec class is on the
# classpath; its constants have the IRIs we declared. Compile alone
# would catch the "no class generated" failure; the main() catches
# wrong-URI bugs.
java_test(
    name = "vocab_test",
    srcs = ["UseGeneratedVocabTest.java"],
    main_class = "example.schemagen.UseGeneratedVocabTest",
    use_testrunner = False,
    deps = [
        ":fixture_vocab",
        # Strict-deps: the test references Resource + Property directly.
        # `fixture_vocab` re-exports them transitively but the compiler
        # wants them on this target's deps list explicitly.
        "@jena_maven//:org_apache_jena_jena_core",
    ],
)

examples/smoke/BUILD.bazel

load("@rules_rdf//rdf:dataset.bzl", "rdf_dataset")
load("@rules_rdf//sparql:defs.bzl", "sparql_query_test")

package(default_visibility = ["//visibility:public"])

rdf_dataset(
    name = "people",
    srcs = ["sample.ttl"],
    in_format = "turtle",
)

# End-to-end: rdf_dataset → sparql_query_test → Jena ARQ engine
# via the registered toolchain → exits 0 because the query returns
# zero rows (both alice and bob have foaf:name).
sparql_query_test(
    name = "no_orphans_gate",
    dataset = ":people",
    query = "no_orphans.rq",
)

examples/validate/BUILD.bazel

load("@rules_jena//jena:defs.bzl", "jena_model")
load("@rules_rdf//validate:defs.bzl", "rdf_validate_test")

package(default_visibility = ["//visibility:public"])

# Jena-aware data primitive (also emits RdfDatasetInfo so it flows
# straight into rules_rdf's rdf_validate_test).
jena_model(
    name = "people",
    srcs = ["data.ttl"],
    in_format = "turtle",
)

# End-to-end SHACL gate via the auto-registered jena_shacl
# toolchain. Every foaf:Person must have a foaf:name; both alice
# and bob conform.
rdf_validate_test(
    name = "people_conform",
    dataset = ":people",
    shapes = "shapes.ttl",
)

Rules & providers#

Generated with Stardoc from the module's .bzl sources.

from docs/ROADMAP.md

rules_jena roadmap

Three releases get from “scaffold” to a full Jena-backed implementation of every rules_rdf toolchain type, plus a small set of user-facing convenience rules. Each row points at the production pattern in ~/Documents/rfcs/kg/java/ that gets ported; see SOURCES.md for the full catalog.

v0.1 (next)

Stand up the shared library and the first toolchain. Goal: prove rules_rdf’s contract works for a Jena backend end-to-end.

  • Port Loader.java (corpus-loading) and Writer.java (deterministic Turtle) plus their tests (WriterTest.java) into a public :rdf_io java_library at the rules_jena root.
  • Implement one toolchain — the SPARQL engine — as a java_binary registered under rules_rdf’s sparql_engine_toolchain_type:
    • Read the SPARQL query path from argv (--query=...).
    • Read the data graph as Turtle from stdin.
    • Emit results (TSV or JSON) on stdout, diagnostics on stderr, non-zero exit on parse / execution failure.
    • Same shape as the gate_query_smoke target in kg/java/BUILD.bazel.
  • Gate the toolchain binary with rules_rdf’s plugin-contract conformance test (the analog of jsonschema_plugin_contract_test).
  • Register the default toolchain in MODULE.bazel.
  • Maven coordinates for jena-arq / jena-core / jena-base / jena-iri / slf4j-simple declared inline (no rules_jvm_external pin yet — defer to v0.2 once the full set of binaries is in scope).

v0.2

Round out the toolchain implementations. Goal: every rules_rdf toolchain type has a Jena-backed default.

  • Port GateHarness.java, Gates.java, GateZeroRows.java, GateShacl.java, GateQuerySmoke.java as additional toolchain-backing binaries — one per gate shape.
  • Implement the SHACL validator toolchain on top of org.apache.jena.shacl.ShaclValidator (mirroring GateShacl).
  • Implement the RDF serializer toolchain on top of RDFDataMgr plus the Writer.java invariants.
  • Implement the OWL reasoner toolchain via ReasonerRegistry.getOWLMicroReasoner() (the same call KgReasoner makes in production).
  • Pin Maven artifacts via rules_jvm_external. Single maven.install block in MODULE.bazel; a locked maven_install.json checked in. Removes the hand-rolled @maven//:org_apache_jena_* references that consumers maintain today.
  • Smoke fixture using a tiny pinned ontology (a few classes, a few SHACL shapes, a handful of .rq files) so every toolchain gets an end-to-end test under //examples/smoke.

v0.3

Expose the higher-level patterns the corpus uses every day. Goal: a downstream consumer can replace kg/java/ with a thin BUILD file that loads from rules_jena.

  • Extract kg/lint/ patterns into a reusable jena_lint rule — orphan / consistency checks driven by a user-supplied query set.
  • Extract kg/rules/ patterns into a jena_reason rule — runs a pinned set of Jena rule files over a Dataset and emits a deterministic inferred Turtle output (mirroring kg_reasoner --check).
  • Provide a jena_corpus macro that takes an ontology dir, a TTL glob, a queries dir and stitches together the gate test_suite the corpus uses today.

from docs/SOURCES.md

Source-of-truth patterns to port

The Jena patterns rules_jena packages as toolchains all exist in production today, in the Aion RFC knowledge-graph tree at ~/Documents/rfcs/kg/java/. This file catalogs which files we extract and what each one teaches.

Reference BUILD files (read-only sources of the wiring):

  • ~/Documents/rfcs/kg/java/BUILD.bazel — the JENA_DEPS list, the :loader, :writer, :gate_harness java_library declarations, plus the gate_* java_tests.
  • ~/Documents/rfcs/kg/java/reasoner/BUILD.bazel — the kg_reasoner java_binary (OWL-MICRO inference).

Files

File (under ~/Documents/rfcs/kg/java/)What it teaches
Loader.javaSingle shared library that loads every TTL under a corpus root into one in-memory Jena Dataset. Every downstream binary depends on this — port becomes the public :rdf_io library at the rules_jena root.
Writer.javaDeterministic Turtle serializer. Stable prefix ordering, stable blank-node labels, byte-stable round-trip. The invariants documented in the file header become the rules_jena serializer toolchain’s contract.
WriterTest.javaRound-trip + parse-equivalence test: write(load(write(model))) byte-equals write(model) and the result is isomorphic to the input. Ports as the rules_jena serializer-toolchain conformance test.
GateHarness.javaOrchestrates a set of SPARQL zero-row checks plus a SHACL conformance check against one Dataset. The “compose multiple gates into one suite” pattern.
Gates.javaShared query-plumbing helpers (load a .rq from disk, execute against a Dataset, collect results). Used by every Gate* binary; ports as a private helper for the SPARQL + SHACL toolchain binaries.
GateZeroRows.javaThe “run one .rq and fail if it returns >0 rows” gate shape. Generalizes to the rules_jena SPARQL toolchain’s zero-row mode.
GateQuerySmoke.javaThe “every .rq under a dir parses + executes” gate shape. The conformance-test analog for SPARQL toolchains.
GateShacl.javaThe “load shapes.ttl + data, run ShaclValidator, fail on non-conforming” gate shape. Becomes the rules_jena SHACL validator toolchain core.
reasoner/KgReasoner.javaOWL-MICRO inference via ReasonerRegistry.getOWLMicroReasoner(), plus a Jena rule-file driver. Deterministic, idempotent output. Becomes the rules_jena OWL reasoner toolchain.

What we do not port (yet)

These exist in the kg/java/ tree but are corpus-specific, not generic Jena tooling — they belong in a downstream consumer, not in rules_jena:

  • KgReport.java, CrossCutting.java — Aion-specific reporting.
  • AionPaths.java — XDG/macOS/Windows config paths (not Jena).
  • BuildSummary.javaSUMMARY.md drift gate (not Jena).
  • Anything under kg/java/edit/, kg/java/lint/, kg/java/metrics/, kg/java/research/ — corpus-specific CLIs. The reusable shapes inside them (lint rules, metric formulas) land as jena_lint / jena_reason in v0.3.

from docs/dataset.md

jena_dataset(name, default_graph, named_graphs) — a Jena Dataset: a default graph plus a set of named graphs addressable by IRI.

Provider-only. Composes jena_model labels. Like jena_model, also emits RdfDatasetInfo (the union of all triples across the default + named graphs) so rules_rdf rules consume it transparently.

load("@rules_jena//jena:defs.bzl", "jena_model", "jena_dataset")

jena_model(name = "core", srcs = ["core.ttl"], in_format = "turtle")
jena_model(name = "facts", srcs = ["facts.ttl"], in_format = "turtle")
jena_model(name = "claims", srcs = ["claims.ttl"], in_format = "turtle")

jena_dataset(
    name = "corpus",
    default_graph = ":core",
    named_graphs = {
        "http://example.org/g/facts": ":facts",
        "http://example.org/g/claims": ":claims",
    },
)

Datasets without named graphs are a degenerate case — for those, use jena_model directly.

jena_dataset

load("@rules_jena//jena:dataset.bzl", "jena_dataset")

jena_dataset(name, default_graph, named_graphs)

A Jena Dataset composed of named-graph jena_models + an optional default graph.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
default_graphA jena_model whose triples form the dataset’s default graph (unnamed). Optional.LabeloptionalNone
named_graphsMap of graph IRI → jena_model label. Each entry becomes a named graph in the resulting Dataset.Dictionary: String -> Labeloptional{}

from docs/defs.md

Public API surface for rules_jena.

Re-exports the v0.2 user-facing rules (Bazel-idiomatic Jena data primitives) + the JENA_DEPS Maven label set shared with anyone writing their own Jena java_binary.

load("@rules_jena//jena:defs.bzl",
     "JENA_DEPS",
     "jena_model", "jena_dataset", "jena_rule_set", "jena_reasoner",
     "JenaModelInfo", "JenaDatasetInfo", "JenaRuleSetInfo", "JenaReasonerInfo")

Pair with the rules_rdf user-facing test rules (sparql_query_test, rdf_validate_test) — jena_model / jena_dataset emit both JenaModelInfo / JenaDatasetInfo AND RdfDatasetInfo, so they’re drop-in replacements for rdf_dataset in any rules_rdf rule.

rules_jena’s MODULE.bazel auto-registers four toolchains satisfying every rules_rdf toolchain type — pulling in rules_jena is enough to run any of sparql_query_test, rdf_validate_test, rdf_transform, rdf_reason. v0.2’s jena_reason build action is the consumer-facing alternative when a downstream rule wants a concrete file artifact instead of the test-shaped rdf_reason.

jena_dataset

load("@rules_jena//jena:defs.bzl", "jena_dataset")

jena_dataset(name, default_graph, named_graphs)

A Jena Dataset composed of named-graph jena_models + an optional default graph.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
default_graphA jena_model whose triples form the dataset’s default graph (unnamed). Optional.LabeloptionalNone
named_graphsMap of graph IRI → jena_model label. Each entry becomes a named graph in the resulting Dataset.Dictionary: String -> Labeloptional{}

jena_model

load("@rules_jena//jena:defs.bzl", "jena_model")

jena_model(name, srcs, base_iri, in_format)

A Jena Model (single RDF graph) declared as Bazel data.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
srcsSource RDF files for this single graph. Concatenated in lexicographic order by Jena tools.List of labelsrequired
base_iriOptional base IRI for resolving relative references in srcs. Empty = none.Stringoptional""
in_formatSerialization of every file in srcs. Mixed formats aren’t supported — pipe through rdf_transform first if you need to combine.Stringoptional"turtle"

jena_reasoner

load("@rules_jena//jena:defs.bzl", "jena_reasoner")

jena_reasoner(name, profile, rule_set)

A Jena reasoner configuration (provider-only).

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
profileBuilt-in profile name or custom. custom requires rule_set.Stringoptional"rdfs"
rule_setA jena_rule_set label. Required iff profile = ‘custom’.LabeloptionalNone

jena_rule_set

load("@rules_jena//jena:defs.bzl", "jena_rule_set")

jena_rule_set(name, rules)

A set of Jena rule files for the rule-engine reasoner.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
rulesJena rule files. Each must follow the rule-engine syntax at https://jena.apache.org/documentation/inference/#rules.List of labelsrequired

JenaDatasetInfo

load("@rules_jena//jena:defs.bzl", "JenaDatasetInfo")

JenaDatasetInfo(default_graph, named_graphs)

A Jena Dataset (collection of named graphs + an optional default graph). Used by rules that need named-graph addressability (Fuseki, multi-graph SPARQL).

FIELDS

NameDescription
default_graphJenaModelInfo | None: triples that live outside any named graph.
named_graphsdict[str, JenaModelInfo]: graph IRI → model. Order-preserving.

JenaModelInfo

load("@rules_jena//jena:defs.bzl", "JenaModelInfo")

JenaModelInfo(files, in_format, base_iri)

A single Jena Model (RDF graph). Provider-only — the files declared on the rule remain the source of truth.

FIELDS

NameDescription
filesdepset[File]: source files concatenated to form the model.
in_formatstr: serialization (turtle, ntriples, nquads, trig, jsonld, rdfxml). Matches the rules_rdf RDF_FORMATS vocabulary.
base_iristr: optional base IRI for relative references in the source files. Empty string = no base.

JenaReasonerInfo

load("@rules_jena//jena:defs.bzl", "JenaReasonerInfo")

JenaReasonerInfo(profile, rule_set)

A Jena reasoner configuration. Either a built-in profile (rdfs, owl-rl, owl-mini, owl-micro) or a custom rule set; never both. Consumed by jena_reason and by the rdf_reasoner_toolchain_type plugin contract.

FIELDS

NameDescription
profilestr: built-in profile name, or empty if custom.
rule_setJenaRuleSetInfo | None: rule set for the custom profile.

JenaRuleSetInfo

load("@rules_jena//jena:defs.bzl", "JenaRuleSetInfo")

JenaRuleSetInfo(files)

A set of Jena rule files consumed by the rule-engine reasoner (Jena’s RETE-based forward/backward inference). See https://jena.apache.org/documentation/inference/ for the rule syntax. Distinct from SPARQL .rq files.

FIELDS

NameDescription
filesdepset[File]: .rule files in the set.

from docs/model.md

jena_model(name, srcs, in_format, base_iri) — declare one RDF graph as a Jena-aware data primitive.

Provider-only: no Bazel actions, no parsed-form artifacts. The srcs files remain the source of truth; downstream rules either read them directly or feed them to a Java tool that parses them into an in-memory Model.

Every jena_model ALSO emits RdfDatasetInfo (the abstract provider from rules_rdf) so it’s a drop-in dataset for any rules_rdf rule:

load("@rules_jena//jena:defs.bzl", "jena_model")
load("@rules_rdf//sparql:defs.bzl", "sparql_query_test")

jena_model(
    name = "ontology",
    srcs = ["ontology.ttl"],
    in_format = "turtle",
)

sparql_query_test(  # works: resolves via RdfDatasetInfo
    name = "ontology_well_formed",
    dataset = ":ontology",
    query = "queries/check.rq",
)

For named-graph use cases see jena_dataset.

jena_model

load("@rules_jena//jena:model.bzl", "jena_model")

jena_model(name, srcs, base_iri, in_format)

A Jena Model (single RDF graph) declared as Bazel data.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
srcsSource RDF files for this single graph. Concatenated in lexicographic order by Jena tools.List of labelsrequired
base_iriOptional base IRI for resolving relative references in srcs. Empty = none.Stringoptional""
in_formatSerialization of every file in srcs. Mixed formats aren’t supported — pipe through rdf_transform first if you need to combine.Stringoptional"turtle"

from docs/providers.md

Provider types for the rules_jena public API.

The data primitives (jena_model, jena_dataset, jena_rule_set, jena_reasoner) are provider-only — they carry references to files + small Jena-shaped config, no build actions. Build-action rules (jena_reason, the rules_rdf-driven rdf_validate_test, etc.) consume them.

Every data-providing rule also emits the abstract RdfDatasetInfo from rules_rdf, so jena_model / jena_dataset are drop-in replacements for rdf_dataset in any rules_rdf rule. Consumers who want Jena-aware features (named graphs, rule sets, OWL profiles) reach for the Jena providers; everyone else stays on the abstract interface.

The names use the package-prefixed convention (JenaXInfo) so that an unwrapped JenaModelInfo import is unambiguous next to the rules_rdf RdfDatasetInfo.

JenaDatasetInfo

load("@rules_jena//jena:providers.bzl", "JenaDatasetInfo")

JenaDatasetInfo(default_graph, named_graphs)

A Jena Dataset (collection of named graphs + an optional default graph). Used by rules that need named-graph addressability (Fuseki, multi-graph SPARQL).

FIELDS

NameDescription
default_graphJenaModelInfo | None: triples that live outside any named graph.
named_graphsdict[str, JenaModelInfo]: graph IRI → model. Order-preserving.

JenaModelInfo

load("@rules_jena//jena:providers.bzl", "JenaModelInfo")

JenaModelInfo(files, in_format, base_iri)

A single Jena Model (RDF graph). Provider-only — the files declared on the rule remain the source of truth.

FIELDS

NameDescription
filesdepset[File]: source files concatenated to form the model.
in_formatstr: serialization (turtle, ntriples, nquads, trig, jsonld, rdfxml). Matches the rules_rdf RDF_FORMATS vocabulary.
base_iristr: optional base IRI for relative references in the source files. Empty string = no base.

JenaReasonerInfo

load("@rules_jena//jena:providers.bzl", "JenaReasonerInfo")

JenaReasonerInfo(profile, rule_set)

A Jena reasoner configuration. Either a built-in profile (rdfs, owl-rl, owl-mini, owl-micro) or a custom rule set; never both. Consumed by jena_reason and by the rdf_reasoner_toolchain_type plugin contract.

FIELDS

NameDescription
profilestr: built-in profile name, or empty if custom.
rule_setJenaRuleSetInfo | None: rule set for the custom profile.

JenaRuleSetInfo

load("@rules_jena//jena:providers.bzl", "JenaRuleSetInfo")

JenaRuleSetInfo(files)

A set of Jena rule files consumed by the rule-engine reasoner (Jena’s RETE-based forward/backward inference). See https://jena.apache.org/documentation/inference/ for the rule syntax. Distinct from SPARQL .rq files.

FIELDS

NameDescription
filesdepset[File]: .rule files in the set.

from docs/reasoner.md

jena_reasoner(name, profile|rule_set) — declare a reasoner configuration.

Provider-only. Either a built-in profile or a custom rule set; the rule rejects both-or-neither.

Built-in profiles map onto Jena’s ReasonerRegistry:

profileJena equivalent
rdfsReasonerRegistry.getRDFSReasoner()
owl-rlReasonerRegistry.getOWLReasoner()
owl-miniReasonerRegistry.getOWLMiniReasoner()
owl-microReasonerRegistry.getOWLMicroReasoner()
customGenericRuleReasoner with the given rule_set.

The Aion production kg_reasoner uses owl-micro plus purpose-written Jena rule files; both shapes have first-class support here.

load("@rules_jena//jena:defs.bzl", "jena_rule_set", "jena_reasoner")

jena_rule_set(name = "kg_rules", rules = glob(["rules/*.rule"]))

jena_reasoner(name = "owl_micro_plus_kg", profile = "custom", rule_set = ":kg_rules")

To actually apply the reasoner to a base model, use jena_reason (which runs a build action) or the abstract rdf_reason rule from rules_rdf (which resolves the reasoner toolchain).

jena_reasoner

load("@rules_jena//jena:reasoner.bzl", "jena_reasoner")

jena_reasoner(name, profile, rule_set)

A Jena reasoner configuration (provider-only).

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
profileBuilt-in profile name or custom. custom requires rule_set.Stringoptional"rdfs"
rule_setA jena_rule_set label. Required iff profile = ‘custom’.LabeloptionalNone

from docs/rules.md

jena_rule_set(name, rules) — a collection of Jena rule files for the rule-engine reasoner.

Provider-only. Consumed by jena_reasoner(profile = "custom") and by the rdf_reasoner_toolchain_type plugin contract when the plugin’s --rules flag points at a file from this set.

Jena rule syntax (the RETE forward-chainer’s input — distinct from SPARQL):

@prefix ex: <http://example.org/> .

[transitiveSubOrg:
    (?a ex:partOf ?b),
    (?b ex:partOf ?c)
    -> (?a ex:partOf ?c)
]

See https://jena.apache.org/documentation/inference/#rules. The file extension is .rule by convention; .txt is tolerated.

jena_rule_set

load("@rules_jena//jena:rules.bzl", "jena_rule_set")

jena_rule_set(name, rules)

A set of Jena rule files for the rule-engine reasoner.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
rulesJena rule files. Each must follow the rule-engine syntax at https://jena.apache.org/documentation/inference/#rules.List of labelsrequired

Conformance#

No gate findings. 10 contested atoms. See how gating works or the full report.

Contested atoms

Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.

AtomResolved hereElsewhere
apple_support 1.24.2 2.2.0 ×1
bazel_skylib 1.8.2 1.9.0 ×2
gazelle 0.36.0 0.30.0 ×50.44.0 ×10.51.0 ×3
nlohmann_json 3.6.1 3.12.0.bcr.1 ×1
protobuf 33.4 34.0.bcr.1 ×2
rules_go 0.60.0 0.39.1 ×5
rules_jvm_external 6.7 6.8 ×4
rules_python 1.7.0 2.0.1 ×1
rules_swift 3.1.2 3.6.1 ×1
upb 0.0.0-20220923-a547704 0.0.0-20230516-61a97ef ×1

Dependencies#

rules_jena in the registry graph — what it depends on (left) and what depends on it (right).

Depends on

platforms1.0.0bazel_skylib1.8.2rules_rdf0.3.0rules_java8.6.1rules_jvm_external6.6rules_shell0.6.1devstardoc0.7.2devrules_jsonschema0.2.0dev

Used by (6 in the registry)

Versions#

8 published versions, newest first. Each resolves to an immutable, integrity-checked archive.

VersionIntegrity (sha256)Source archive
0.3.2 latest DExmQ0CzGv67BnxG… tag archive ↗
0.3.1 GBmW1uJ2WGOYF3TP… tag archive ↗
0.3.0 emDLuGr7MqRD3kWI… tag archive ↗
0.2.1 liREurkFifroz6Xj… tag archive ↗
0.2.0 IKJuvvA2njacYd18… tag archive ↗
0.1.1 QgsC3SKS7leHJzn8… tag archive ↗
0.1.0 F8PKL8V2zwCEGZj3… tag archive ↗
0.0.1 UMxLBMpPQxAABfjH… tag archive ↗

Changelog#

All notable changes to rules_jena. The format is loosely Keep a Changelog — version headers mirror the published bazel-registry entries.

0.3.1 — jena_schemagen rule

  • New jena_schemagen(name, dataset, package, classname, namespace, …) macro: generate a Java vocabulary class (Resource + Property constants) from any JenaModelInfo or RdfDatasetInfo dataset via Apache Jena’s built-in jena.schemagen tool. Resolves the “I need typo-proof Schema.Person / Prov.Entity constants from RDF datasets” need that Jena has been able to satisfy since forever but rules_jena didn’t expose.
  • Companion JenaSchemagenInfo provider, public :jena_runtime java_library re-exporting jena-arq / core / base / iri / slf4j so consumers across module boundaries can compile generated Java without redeclaring jena_maven.
  • MODULE.bazel adds org.apache.jena:jena-cmds:5.2.0 (schemagen lives in jena-cmds, not jena-arq / core).
  • end-to-end test under examples/schemagen/: a fixture ontology generates a Spec.java whose constants are asserted by a java_test.
  • Three real gotchas documented inline (verified against jena-cmds 5.2.0): -e N3 not --encoding TTL, -n not --classname, stdout capture (not -o <path> — schemagen treats not-yet- existing paths as directories and writes <path>/<classname>.java inside).

0.3.0 — rules_rdf 0.3 dep bump

0.2.1 — binary RDF formats + rules_rdf 0.2 dep bump

  • All four Jena toolchain binaries (jena_sparql, jena_shacl, jena_riot, jena_reasoner_bin) now accept rdfthrift and rdfprotobuf as --in-format values. jena_riot additionally emits both formats via --out-format (RDFFormat.RDF_THRIFT / RDFFormat.RDF_PROTO). Useful as cached intermediate forms in long pipelines — significantly faster to parse than Turtle for large datasets.
  • rules_rdf dep bumped to 0.2.0 to pick up the same RDF_FORMATS vocabulary on the abstract side + the new rdf_reason / rdf_transform build-action rules.

0.2.0 — Bazel-idiomatic Jena API + full rules_rdf backend

Four provider-only data primitives:

  • jena_model(name, srcs, in_format, base_iri) — single Jena Model. Emits both JenaModelInfo and RdfDatasetInfo so it’s drop-in for rules_rdf rules.
  • jena_dataset(name, default_graph, named_graphs) — composed of one or more jena_model labels, addressable by graph IRI. Also emits RdfDatasetInfo (flattened union).
  • jena_rule_set(name, rules) — collection of Jena .rule files for the RETE reasoner.
  • jena_reasoner(name, profile|rule_set) — built-in profile (rdfs / owl-rl / owl-mini / owl-micro) or custom with a rule set.

Three new java_binaries, each satisfying the corresponding rules_rdf plugin contract:

  • //jena/shacl:jena_shaclrdf_validator_toolchain_type.
  • //jena/riot:jena_riotrdf_serializer_toolchain_type.
  • //jena/reasoner:jena_reasoner_binrdf_reasoner_toolchain_type.

All four toolchains (sparql + shacl + riot + reasoner) auto-register in MODULE.bazel — pulling in rules_jena gives consumers a complete rules_rdf backend with zero configuration.

Conformance tests run rules_rdf’s contract driver against every binary; all four pass. End-to-end smoke examples/validate/people_conform chains jena_modelrdf_validate_test → registered jena_shacl toolchain.

Stardoc reference docs for every public .bzl. bazel test //... runs 12/12 (6 stardoc diff_tests + 4 conformance + 1 sparql smoke

  • 1 shacl smoke).

0.1.1 — public JENA_DEPS + stardoc reference docs

  • Public JENA_DEPS constant in //jena:defs.bzl — the five Maven labels every Jena-using java_binary depends on, now re-exportable by downstream consumers (load("@rules_jena//jena:defs.bzl", "JENA_DEPS")). Replaces the inlined list previously hard-coded in jena/sparql/BUILD.bazel.
  • Stardoc-generated reference in docs/bazel run //docs:update regenerates docs/defs.md from the .bzl docstrings; a diff_test gate keeps the committed markdown in sync with the source.

0.1.0 — first concrete implementation: jena_sparql

  • Maven dep pinning via rules_jvm_external: Apache Jena 5.2.0 (jena-arq, jena-core, jena-base, jena-iri, jena-shacl)
    • slf4j-simple 2.0.16. Committed maven_install.json.
  • jena_sparqljava_binary satisfying rules_rdf’s sparql_engine_toolchain_type contract. ARQ-backed; supports SELECT / ASK / CONSTRUCT / DESCRIBE; emits TSV / CSV / JSON / SRX / Turtle; honors --fail-on-nonempty for zero-row gates.
  • //jena:jena_sparql_toolchain_def auto-registered by MODULE.bazel — consumers get the toolchain for free.
  • Conformance gate: //jena:jena_sparql_conforms runs the rules_rdf contract driver. All four scenarios pass against the real Jena binary.
  • End-to-end smoke (examples/smoke/) — FOAF dataset + zero-row SPARQL gate through the registered toolchain.
  • .bazelrc pins --java_runtime_version=remotejdk_21 so builds don’t depend on host JAVA_HOME.

0.0.1 — scaffold

  • Initial scaffold via rels scaffold. No public API yet.

← All modules