rules_jena
API reference, generated from the module’s .bzl docstrings (stardoc).
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) andWriter.java(deterministic Turtle) plus their tests (WriterTest.java) into a public:rdf_iojava_libraryat the rules_jena root. - Implement one toolchain — the SPARQL engine — as a
java_binaryregistered underrules_rdf’ssparql_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_smoketarget inkg/java/BUILD.bazel.
- Read the SPARQL query path from argv (
- Gate the toolchain binary with
rules_rdf’s plugin-contract conformance test (the analog ofjsonschema_plugin_contract_test). - Register the default toolchain in
MODULE.bazel. - Maven coordinates for
jena-arq/jena-core/jena-base/jena-iri/slf4j-simpledeclared inline (norules_jvm_externalpin 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.javaas additional toolchain-backing binaries — one per gate shape. - Implement the SHACL validator toolchain on top of
org.apache.jena.shacl.ShaclValidator(mirroringGateShacl). - Implement the RDF serializer toolchain on top of
RDFDataMgrplus theWriter.javainvariants. - Implement the OWL reasoner toolchain via
ReasonerRegistry.getOWLMicroReasoner()(the same callKgReasonermakes in production). - Pin Maven artifacts via
rules_jvm_external. Singlemaven.installblock inMODULE.bazel; a lockedmaven_install.jsonchecked 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
.rqfiles) 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 reusablejena_lintrule — orphan / consistency checks driven by a user-supplied query set. - Extract
kg/rules/patterns into ajena_reasonrule — runs a pinned set of Jena rule files over aDatasetand emits a deterministic inferred Turtle output (mirroringkg_reasoner --check). - Provide a
jena_corpusmacro that takes an ontology dir, a TTL glob, a queries dir and stitches together the gatetest_suitethe corpus uses today.
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— theJENA_DEPSlist, the:loader,:writer,:gate_harnessjava_librarydeclarations, plus thegate_*java_tests.~/Documents/rfcs/kg/java/reasoner/BUILD.bazel— thekg_reasonerjava_binary(OWL-MICRO inference).
Files
File (under ~/Documents/rfcs/kg/java/) | What it teaches |
|---|---|
Loader.java | Single 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.java | Deterministic 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.java | Round-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.java | Orchestrates a set of SPARQL zero-row checks plus a SHACL conformance check against one Dataset. The “compose multiple gates into one suite” pattern. |
Gates.java | Shared 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.java | The “run one .rq and fail if it returns >0 rows” gate shape. Generalizes to the rules_jena SPARQL toolchain’s zero-row mode. |
GateQuerySmoke.java | The “every .rq under a dir parses + executes” gate shape. The conformance-test analog for SPARQL toolchains. |
GateShacl.java | The “load shapes.ttl + data, run ShaclValidator, fail on non-conforming” gate shape. Becomes the rules_jena SHACL validator toolchain core. |
reasoner/KgReasoner.java | OWL-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.java—SUMMARY.mddrift 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 asjena_lint/jena_reasonin v0.3.
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| default_graph | A jena_model whose triples form the dataset’s default graph (unnamed). Optional. | Label | optional | None |
| named_graphs | Map of graph IRI → jena_model label. Each entry becomes a named graph in the resulting Dataset. | Dictionary: String -> Label | optional | {} |
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| default_graph | A jena_model whose triples form the dataset’s default graph (unnamed). Optional. | Label | optional | None |
| named_graphs | Map of graph IRI → jena_model label. Each entry becomes a named graph in the resulting Dataset. | Dictionary: String -> Label | optional | {} |
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| srcs | Source RDF files for this single graph. Concatenated in lexicographic order by Jena tools. | List of labels | required | |
| base_iri | Optional base IRI for resolving relative references in srcs. Empty = none. | String | optional | "" |
| in_format | Serialization of every file in srcs. Mixed formats aren’t supported — pipe through rdf_transform first if you need to combine. | String | optional | "turtle" |
jena_reasoner
load("@rules_jena//jena:defs.bzl", "jena_reasoner")
jena_reasoner(name, profile, rule_set)
A Jena reasoner configuration (provider-only).
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| profile | Built-in profile name or custom. custom requires rule_set. | String | optional | "rdfs" |
| rule_set | A jena_rule_set label. Required iff profile = ‘custom’. | Label | optional | None |
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| rules | Jena rule files. Each must follow the rule-engine syntax at https://jena.apache.org/documentation/inference/#rules. | List of labels | required |
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
| Name | Description |
|---|---|
| default_graph | JenaModelInfo | None: triples that live outside any named graph. |
| named_graphs | dict[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
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
| Name | Description |
|---|---|
| profile | str: built-in profile name, or empty if custom. |
| rule_set | JenaRuleSetInfo | 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
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| srcs | Source RDF files for this single graph. Concatenated in lexicographic order by Jena tools. | List of labels | required | |
| base_iri | Optional base IRI for resolving relative references in srcs. Empty = none. | String | optional | "" |
| in_format | Serialization of every file in srcs. Mixed formats aren’t supported — pipe through rdf_transform first if you need to combine. | String | optional | "turtle" |
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
| Name | Description |
|---|---|
| default_graph | JenaModelInfo | None: triples that live outside any named graph. |
| named_graphs | dict[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
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
| Name | Description |
|---|---|
| profile | str: built-in profile name, or empty if custom. |
| rule_set | JenaRuleSetInfo | 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
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:
profile | Jena equivalent |
|---|---|
rdfs | ReasonerRegistry.getRDFSReasoner() |
owl-rl | ReasonerRegistry.getOWLReasoner() |
owl-mini | ReasonerRegistry.getOWLMiniReasoner() |
owl-micro | ReasonerRegistry.getOWLMicroReasoner() |
custom | GenericRuleReasoner 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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| profile | Built-in profile name or custom. custom requires rule_set. | String | optional | "rdfs" |
| rule_set | A jena_rule_set label. Required iff profile = ‘custom’. | Label | optional | None |
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
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| rules | Jena rule files. Each must follow the rule-engine syntax at https://jena.apache.org/documentation/inference/#rules. | List of labels | required |