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.
| Latest | 0.3.2 |
|---|---|
| Versions | 8 |
| Category | Bazel rules |
| Maintainers | Matt Marshall |
| Registry | https://registry.tbzl.dev/modules/rules_jena/ |
| Source | github.com/tomato-bazel/rules_jena |
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. Seedocs/model.md,docs/dataset.md,docs/rules.md,docs/reasoner.md. Every model + dataset also emitsRdfDatasetInfoso 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 chainjena_model→rdf_validate_test→jena_shacltoolchain.
Deferred to v0.3 (see docs/ROADMAP.md):
jena_reasonbuild action (today’srdf_reasontest 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_fusekiHTTP-server dev runner.- Port
Loader.java+ deterministicWriter.javafrom the Aionkg/java/corpus as a public:jena_iojava_library. - Severity-aware SHACL filtering (today
--severityis 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 viarules_jvm_externalwith a committedmaven_install.json. Same artifact set as the productionkg/java/JENA_DEPSconstant.JENA_DEPS(from@rules_jena//jena:defs.bzl) — the five Maven labels every Jena-usingjava_binaryneeds, exposed as a publicly re-exportable Starlark constant. Downstream consumersload("@rules_jena//jena:defs.bzl", "JENA_DEPS")and spread it into theirdepsattr instead of hand-rolling their own list. Stardoc reference indocs/defs.md.//jena/sparql:jena_sparql—java_binaryimplementingrules_rdf’ssparql_engine_toolchain_typeplugin 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-nonemptydrives the zero-row gate idiom.
- CONSTRUCT + DESCRIBE all supported.
//jena:jena_sparql_toolchain_def— toolchain registration. Auto-registered inMODULE.bazelso consumers don’t have to.- Conformance test (
//jena:jena_sparql_conforms) — runsrules_rdf’srdf_plugin_contract_testdriver 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:allpasses.
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.javafrom~/Documents/rfcs/kg/java/as public//jena:loader+//jena:writerjava_librarytargets.
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 type | Jena backing | Pattern source |
|---|---|---|
sparql_engine_toolchain_type | ARQ (org.apache.jena.query.QueryExecutionFactory) — read .rq from argv, .ttl from stdin, results to stdout | gate_query_smoke in kg/java/BUILD.bazel |
shacl_validator_toolchain_type | org.apache.jena.shacl.ShaclValidator — shapes + data graph in, conformance report out | gate_shacl / GateShacl.java |
rdf_serializer_toolchain_type | Jena’s RDFDataMgr + the deterministic Turtle writer patterns from Writer.java (byte-stable round-trip + parse-equivalence) | Writer.java + WriterTest.java |
owl_reasoner_toolchain_type | ReasonerRegistry.getOWLMicroReasoner() — matches what kg_reasoner runs in production today | kg/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-memoryDataset”. 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 aDataset.GateZeroRows.java,GateQuerySmoke.java,GateShacl.java— the three reusable PR-gate shapes.KgReasoner.java(underkg/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_DEPSset used by the source corpus today —jena-arq,jena-core,jena-base,jena-iri, plusslf4j-simplefor 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) 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.
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— 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.
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
| 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 | {} |
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
| 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
| Name | Description |
|---|---|
| files | depset[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
| 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" |
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
| 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
| Name | Description |
|---|---|
| files | depset[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:
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 |
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
| 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 |
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.
| Atom | Resolved here | Elsewhere |
|---|---|---|
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#
Depends on
Used by (6 in the registry)
Versions#
8 published versions, newest first. Each resolves to an immutable, integrity-checked archive.
| Version | Integrity (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 anyJenaModelInfoorRdfDatasetInfodataset via Apache Jena’s built-injena.schemagentool. Resolves the “I need typo-proofSchema.Person/Prov.Entityconstants from RDF datasets” need that Jena has been able to satisfy since forever but rules_jena didn’t expose. - Companion
JenaSchemagenInfoprovider, public:jena_runtimejava_libraryre-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 aSpec.javawhose constants are asserted by ajava_test. - Three real gotchas documented inline (verified against jena-cmds
5.2.0):
-e N3not--encoding TTL,-nnot--classname, stdout capture (not-o <path>— schemagen treats not-yet- existing paths as directories and writes<path>/<classname>.javainside).
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 acceptrdfthriftandrdfprotobufas--in-formatvalues.jena_riotadditionally 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_rdfdep bumped to0.2.0to pick up the sameRDF_FORMATSvocabulary on the abstract side + the newrdf_reason/rdf_transformbuild-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 bothJenaModelInfoandRdfDatasetInfoso it’s drop-in for rules_rdf rules.jena_dataset(name, default_graph, named_graphs)— composed of one or morejena_modellabels, addressable by graph IRI. Also emitsRdfDatasetInfo(flattened union).jena_rule_set(name, rules)— collection of Jena.rulefiles for the RETE reasoner.jena_reasoner(name, profile|rule_set)— built-in profile (rdfs/owl-rl/owl-mini/owl-micro) orcustomwith a rule set.
Three new java_binaries, each satisfying the corresponding rules_rdf plugin contract:
//jena/shacl:jena_shacl→rdf_validator_toolchain_type.//jena/riot:jena_riot→rdf_serializer_toolchain_type.//jena/reasoner:jena_reasoner_bin→rdf_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_model →
rdf_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_DEPSconstant in//jena:defs.bzl— the five Maven labels every Jena-usingjava_binarydepends on, now re-exportable by downstream consumers (load("@rules_jena//jena:defs.bzl", "JENA_DEPS")). Replaces the inlined list previously hard-coded injena/sparql/BUILD.bazel. - Stardoc-generated reference in
docs/—bazel run //docs:updateregeneratesdocs/defs.mdfrom the.bzldocstrings; adiff_testgate 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-simple2.0.16. Committedmaven_install.json.
jena_sparql—java_binarysatisfying rules_rdf’ssparql_engine_toolchain_typecontract. ARQ-backed; supports SELECT / ASK / CONSTRUCT / DESCRIBE; emits TSV / CSV / JSON / SRX / Turtle; honors--fail-on-nonemptyfor zero-row gates.//jena:jena_sparql_toolchain_defauto-registered byMODULE.bazel— consumers get the toolchain for free.- Conformance gate:
//jena:jena_sparql_conformsruns 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. .bazelrcpins--java_runtime_version=remotejdk_21so builds don’t depend on hostJAVA_HOME.
0.0.1 — scaffold
- Initial scaffold via
rels scaffold. No public API yet.