Skip to content

EN 16931 Semantic JSON 0.9.5

Choose a tag to compare

@github-actions github-actions released this 07 Oct 22:49
· 77 commits to main since this release
Immutable release. Only release title and notes can be modified.

Added

  • Six negative fixtures under examples/invalid/, run by the fixture manifest over the Java, the
    TypeScript and the C# reader: extension-number-exponent-overflow and -underflow
    (ESJ-L1-EXT-NUMBER), value-depth-32 and value-depth-33 (ESJ-L1-JSON-TYPE, then
    ESJ-L1-LIMIT: the walk past a structure inside values), path-syntax-with-array-value
    (ESJ-L1-PATH-SYNTAX and ESJ-L1-JSON-TYPE) and values-deep-array (ESJ-L1-ENVELOPE-VALUE).
  • de.bsnsoft.esj.Preview, an annotation for what is published to be used and judged and may
    change in any minor release. It marks the packages …typed.v2026, …rules.en16931.v2026,
    …upgrade and …b2c, the types MinorUnits, PackFetcher, PackRecipe, PackRecipes,
    ContainerChecks, InvoiceAttachments and En16931V2026Pack, and the method
    RulePackSource.currencyMinorUnits(). The generator writes the package comment of the 2026
    view with it.
  • Registry.isPreview(): whether a registry describes an edition this project ships as a preview.
  • de.bsnsoft.esj.imports.InvoiceReader, ImportResult read(byte[] xml): StreamingReader and
    XrImporter implement it, and PdfInvoiceImporter.importPdf hands the attachment to one.
  • The package de.bsnsoft.esj.xml in esj-core, the front door of an XML invoice:
    InvoiceSyntax with of(namespace, localName), EncodingMode, XmlEncodingReport with
    of(byte[]), and XmlEncodingException. Both readers, the syntax engine and the PDF container
    name a syntax and an encoding with these types.
  • Registry.en16931WithXrechnung(): the core model with the XRechnung extension, built once; the
    readers, the renderers and XrExporter use it by default.
  • EsjLimitException.bound() names the bound that was reached as an EsjLimitException.Bound:
    the setting (maxInputBytes, maxPages, maxRuntime, …), its value and its unit. Every bound
    of every module names it.
  • RenderEngineException, the failure of the rendering machinery, which RenderException stood
    for itself before.
  • CiiWriter.semanticModel(), CiiWriter.supports(String), UblWriter.semanticModel() and
    UblWriter.supports(String).
  • Every jar names its module: Automatic-Module-Name is de.bsnsoft.esj. followed by the
    artifact identifier without esj- (de.bsnsoft.esj.core, …); MavenCoordinatesTest holds every
    published jar to it.
  • The Maven profile api-check compares the API of every library module with the release
    esj.api-baseline names, with japicmp, leaving out internal packages, the preview packages and
    everything marked @Preview. It reports and does not fail before 1.0.0; the CI job API compared
    with the last release
    keeps the report (docs/releasing.md). Against 0.9.4 it names 124 classes
    with incompatible changes, all of them the moves, renames and removals of the migration table and
    the preview marks.
  • The rule files of both bundled packs, as their manifests name them, are validated against
    rules/rule.schema.json on every build; the 2026 pack's test is part of what
    bin/without-edition-2026.sh removes.
  • Three negative fixtures carry, in a member name, every class of character SPEC.md section 9.5
    escapes: path-syntax-terminal-characters (ESJ-L1-PATH-SYNTAX),
    owner-token-terminal-characters (ESJ-L1-OWNER-TOKEN) and
    envelope-member-terminal-characters (ESJ-L1-ENVELOPE-MEMBER). The fixture manifest records
    the subject of a finding where section 9.5 requires one — where the path is empty, and on a
    finding of layer L3 — and run.py and the manifest tests of both bindings compare it there; a
    binding's validate answer carries subject beside path and code.
  • docs/compatibility.md: what a release may change from 1.0.0 — the format, the command line,
    the Java libraries, the data they ship — and the rules the Java API keeps; docs/java-api.md
    lists every public package as API, preview or internal.
  • Registry.editionKey(), Registry.defaultEditionKey() and Registry.editionKeys(): an edition
    is named three ways and each has its method — the key (2017), edition() (the title) and
    semanticModel() (the spelling of a document).
  • de.bsnsoft.esj.render.PaymentCode (TEMPLATE, DRAW, OMIT), what RenderOptions says
    about the EPC QR code of the letter.

Changed

  • esj render --html is held to --max-output-bytes (64 MiB, 1 GiB under --limits large), as
    every XML document the tool writes is: the page is measured in bytes of UTF-8 while it is
    written, and one past the bound leaves with exit code 7 and nothing written, rather than being
    finished in memory first. In the library the bound is RenderOptions.maxHtmlBytes()
    (withMaxHtmlBytes(long), 1 GiB by default) and is reached with an EsjLimitException.
  • esj-render replaces U+007F and the C1 controls with a space in every form — the HTML
    rendering and the report carried them as they stood, the PDF printed a question mark — and
    turns U+0085, U+2028 and U+2029 into line feeds in all of them; one class holds the sets for
    every form.
  • dist/package.sh smoke compares a container image only when dist/package.sh docker built it
    from the jar it is compared with, and fails when the image that target built is gone or stale;
    an older image of the same tag is named and not compared. dist/smoke.sh takes a relative path
    in a command relative to the directory it was run from.
  • bin/without-edition-2026.sh makes its copy under $TMPDIR and removes it when it ends;
    --keep keeps it.
  • -Dsurefire.failIfNoSpecifiedTests=false lets mvn -Dtest=<class> -pl <module> -am pass the
    modules without that test; without it, a pattern that matches no test still fails.
  • esj-render's sRGB profile is recorded as compared byte for byte with the file the
    International Color Consortium publishes (icc/README.md, docs/sources.md).
  • The bindings carry their publisher's names and the project's version: the npm package is
    @bsnsoft/esj (was en16931-semantic-json), the C# package, assembly and namespace
    BSNSoft.Esj (was En16931.SemanticJson, projects under bindings/csharp/BSNSoft.Esj*). The C#
    build reads the version from pom.xml; npm run sync-version writes it into package.json and
    package-lock.json, and a test fails while they differ. Nothing is published yet.
  • EN 16931-1:2026 is a preview, and says so: esj --version prints
    semantic model registries 2017, 2026 (preview), esj inspect and esj validate print
    Semantic model: EN16931-1:2026 (preview), the validation report writes (preview) or
    (Vorschau) beside the edition, esj upgrade writes an info: line where the edition it reads
    or writes is one, and esj --list-packs marks the pack en16931-2026/0.1. The JSON output is
    unchanged. README.md, SPEC.md (section 1; the format stays 0.1), docs/editions.md,
    docs/java-api.md and the FAQ say so too.
  • The Javadoc leaves out every package whose name contains internal.
  • esj-syntax and esj-render declare Saxon-HE, which they call directly; esj-cli takes
    esj-typed in test scope only, so the self-contained jar no longer carries the typed view it
    never loads.
  • One set of characters that steer a terminal, Esj.steersATerminal(int) and
    Esj.isBidiControl(int) in esj-core, is used by every text output: the messages of
    esj-core, esj-rules and esj-pdf, the lines of esj list, esj inspect, esj diff,
    esj extract --list and of every report, and the error stream. The JSON reports write the same
    characters as JSON escapes. Until now list, inspect and diff wrote C1 controls (CSI,
    NEXT LINE), U+061C, U+2028 and U+2029 as they stood, and a message of a registry quoted its
    content unescaped. esj get still writes a value raw. esj-render takes the bidirectional
    controls from there as well and adds the interlinear annotation characters U+FFF9–U+FFFB,
    which only a rendering replaces; the messages of esj-rules and esj-pdf write \u with
    lowercase digits, as esj-core does.
  • Every command that reads a document holds the five-minute deadline where --max-runtime names
    none: convert, upgrade, inspect, extract, get, list, diff, canonicalize, and
    embed without --verapdf, as validate and render did. Exit code 7 and no verdict. Over
    conformance/scale (80 MB of UBL and CII, rich and dense lines, --limits large) each of them
    ends in 2 to 22 s; --importer xslt takes 2 minutes over 25 MB and needs a larger
    --max-runtime from about 40 MB.
  • examples/smallest-valid.esj.json states BT-110 (0): it is VALID through both syntaxes, where
    --via ubl said INDETERMINATE (exit code 9) because UBL requires the tax amount beside a VAT
    breakdown. It has 28 terms, and removing any of them ends the verdict through one of the two.
  • XmlEncodingReport has decodes() and XmlEncodingException has repairable(); the earlier
    constructors stay.
  • One exception hierarchy: EsjException is the abstract root of every exception the libraries
    throw, no longer sealed. XrException, BindingException, SyntaxException, PdfException,
    RenderException, PackException, RulePackException, DerivationException,
    MissingValueException, ValueTypeException, BuildException and
    PolicyPreconditionException extend it. RenderException is abstract and sealed, its kinds
    final: RenderEngineException, TemplateException, RenderContentException.
  • Every bound of every module raises EsjLimitException, which is no longer final and no longer
    belongs to a module's hierarchy: catch (PdfException e) or catch (BindingException e) no
    longer catches a limit. The messages are the ones of 0.9.4.
  • PdfInvoiceImporter.importPdf(byte[]) reads the attachment with the StreamingReader, as the
    command line does; it was the importer of esj-xr. The document is the one esj convert writes
    for the same file, and a refusal is the streaming reader's (BindingSyntaxException,
    BindingFormatException). A reader handed in is used as it is. The command line is unchanged.
  • esj-bindings needs neither esj-xr nor Saxon-HE (runtime dependencies 8.7 MB → 1.1 MB), and
    esj-pdf no longer needs esj-xr (12.7 MB → 5.1 MB); both declare it for their tests only.
  • XrImporter reads with one verb, as StreamingReader does: read(byte[]), readUbl,
    readCii and readXr return the ImportResult.
  • XmlEncodingException is thrown by both readers and is an EsjException, not an
    XrException; a recode that does not decode, which a report made of the same bytes rules out,
    raises it rather than an XrFormatException.
  • The command line turns a bound of any library into exit code 7 in one place. A bound met while
    the PDF validation report is drawn, or while esj embed writes the attachment, now leaves with
    7 where it left with 5, "internal error".
  • Options are final classes with one convention: defaults() and one withX(…) per setting,
    equals and the accessors of before. That holds for Limits, ReaderOptions,
    WriterOptions, SyntaxOptions, PdfLimits, EmbedOptions, RenderOptions,
    TotalsOptions, AuthoringOptions and UpgradeOptions; none has a builder or a public
    constructor any more.
  • A value that changes with a release is a method rather than a constant compiled into the
    caller: the format version, the default edition, the version of a bundled rule pack and the
    defaults of every options class.
  • One Severity (ERROR, WARNING, INFO) and one ValidationStatus in
    de.bsnsoft.esj.validate for every check: the syntax engine, the rule engine, the container
    checks of a PDF and the structural validator. The reports, the JSON output and the ledgers keep
    the words of each source — fatal and information for an artefact, fatal and info for a
    rule pack.
  • Term is a final class with the accessors of the record; a later release can give it a member
    without breaking a caller.
  • An array a method of the API returns is a copy: ExportResult.xr(), AttachmentContent.bytes()
    and PdfContainer.xmpPacket() handed out the array they hold.
  • The generated views, editors and step builders, Coded and the steps of InvoiceSteps are
    sealed; EditorList, ValueList, IdentifierList and SchemedIdentifierList say they are not
    for implementation.
  • The PDF engine of esj-render and the report renderer are in de.bsnsoft.esj.render.internal;
    PdfRenderer, HtmlRenderer, RenderOptions, RenderTemplate, the enums and the exceptions
    stay.
  • A PDF validation report that reaches its page bound says so — the 2 000 pages a report is drawn
    within, which --max-pages does not move — where the line named --max-pages. Exit code 7.

Removed

  • esj-generator is no longer published on Maven Central and is no longer managed by esj-bom.
  • XrLimitException, BindingLimitException, SyntaxLimitException, PdfLimitException and
    RenderLimitException; XrSyntax and BindingSyntax; XrImporter.importUbl, importCii,
    importXml, fromXr and defaultRegistry(); Esj.forMessage, forSubject and abbreviated.
    The migration table below names what takes their place.

Fixed

  • esj render in the letter layout — the default since 0.9.2 — left with exit code 5, "internal
    error", where the invoice number (BT-1) or the buyer reference (BT-10) carried a line feed,
    which ESJ allows in every text; the generic layout left with 2 on the same invoice number. Both
    layouts draw such a document now. A line end of any kind — CR LF, CR, VT, FF, U+0085, U+2028,
    U+2029 — breaks a block as a line feed does and is a space on a line that has to stay one: the
    page footer, the head of a following page, a figure of the totals, the footer of the PDF report.
    No character the embedded faces have no glyph for reaches them.
  • U+061C ARABIC LETTER MARK reached the HTML rendering and the HTML report, although the
    renderings replace the characters that direct the reading order with a space. HTML, PDF and
    report now replace one set: U+061C, U+200E, U+200F, U+202A–U+202E, U+2066–U+2069 and
    U+FFF9–U+FFFB.
  • The EPC QR code (GiroCode) of the letter dropped an element only where it carried a line feed
    or a carriage return; U+2028, U+2029, U+0085, VT and FF passed into the payload, so a reader
    that splits lines where Unicode does would read the account and the amount one line too far
    down. No element carries a line end of any kind, another control character, a character that
    directs the reading order or half a surrogate pair now: where the beneficiary, the remittance
    information or the invoice number standing in for it holds one, the letter draws no code and
    says under Further details which element it was.
  • Render templates: a reference was checked as a name, so a symbolic link beside the template
    led out of its directory, and a link to /dev/zero or a small PNG that declares a vast picture
    ran the heap out. A reference is now checked as the file it reaches — a link out of the
    directory and anything that is not a regular file are refused — a file is refused by its size
    before it is read (32 MiB), an image by the size its header states before it is decoded
    (36 million pixels, a page at 600 dots per inch), and the template file itself is read to
    32 MiB at most. Each refusal names the file and leaves with exit code 2, as every template error
    does.
  • TypeScript: a number inside extensions whose canonical form is long (1e500000000,
    1e-500000000, 1e999999999, 0. and a million zeros) cost up to 600 MiB, minutes, or an
    uncaught RangeError from readDocument. The length of the canonical form is computed before
    any digit is written, the exponent saturated, as in Java and C#: ESJ-L1-EXT-NUMBER at once.
    canonicalNumber throws EsjError (ESJ-L1-EXT-NUMBER) for such a number.
  • TypeScript: the reader streams. It judges each member where the text reaches it and walks past
    what it refuses without building it: 64 MiB of [0,0,…] where a string belongs cost 2.6 GiB and
    ran out of memory under a 1 GiB heap, now 0.5 s and less than 300 MiB. Where its findings
    differed from Java's they no longer do: the value under a name that is no path is judged, a
    finding confined to one member stands before a JSON error after it, an undefined envelope member
    ends the read before broken text behind it, a JSON error or a limit inside a member of values
    names that member's path, and a member name is held to the larger of the string and path bound.
  • TypeScript: reader and canonical writer keep the containers they open on a stack. A raised
    maxExtensionDepth reads and canonicalizes a document 60 000 levels deep, where the parser
    overflowed the stack and readDocument turned that into TypeError: value is not iterable;
    readDocument now passes on any error that is not a finding unchanged.
  • TypeScript: the canonical and the pretty form refuse a string with a lone surrogate with
    EsjError (ESJ-L1-SURROGATE), as Java and C# do, instead of writing U+FFFD; semanticDigest
    and documentDigest reject with it rather than throw.
  • TypeScript: npm run build type-checks again (TypeScript 7 loads no Node types unasked).
  • C#: the reader answers as the Java one where it did not. An envelope member of the wrong JSON
    type is refused at its first token (a deep array there was ESJ-L1-LIMIT, now
    ESJ-L1-ENVELOPE-VALUE); a number token longer than the string bound is ESJ-L1-LIMIT wherever
    it stands (was ESJ-L1-JSON-TYPE inside values), and so is a member name longer than the
    larger of the string and path bound.
  • A document whose bytes do not decode in the charset it declares and are none of UTF-8, UTF-16,
    ISO-8859-1 and Windows-1252 — Shift_JIS or EUC-JP over bytes that spell no character of it,
    US-ASCII over Latin-1 — was read with U+FFFD where the bytes did not decode, without the note
    ENCODING_REPAIRED and under --strict as well, by every command but validate. Both readers
    now refuse it in either mode: exit code 2 naming the charset, and XML-ENCODING under
    esj validate. The same holds behind a byte order mark whose charset the bytes do not spell.
    Bytes that are UTF-8 under another declaration are read as UTF-8, and a byte Windows-1252
    leaves undefined as ISO-8859-1, each with the note.
  • No XML parser of the platform is handed bytes it cannot decode, so none writes a line of its own
    ([Fatal Error] …) to the error stream. A document declaring UTF-8 with such a byte before its
    root element was refused by every command as being of no syntax this tool reads; it is now
    recoded with the note, like any other.
  • docs/cli.md: esj extract --out follows a symbolic link at the path the caller names.
    docs/validation-measurements.md: the official Schematron is superlinear where a line-level
    assertion fails on every line.
  • TypeScript and C#: a message and a subject escape the characters of SPEC.md section 9.5 the
    Java implementation escapes. Both let the C1 controls, U+2028, U+2029 and U+061C through, and
    TypeScript U+200E and U+200F as well; TypeScript wrote \u001B where Java and C# write
    \u001b, and ended a cut excerpt in … where they write .... TypeScript exports
    steersATerminal and isBidiControl, C# has Esj.SteersATerminal and Esj.IsBidiControl.
  • TypeScript: a finding about a member of source names it source.syntax (was
    source["syntax"]), and one about a name repeated in values names values (was the member
    access of the name), as Java and C# do.

Security

  • The release archives and the container image carry a build provenance attestation, signed
    through Sigstore and kept by GitHub: gh attestation verify <archive> --repo bsnsoft/esj, and
    gh attestation verify oci://ghcr.io/bsnsoft/esj:<version> --repo bsnsoft/esj for the image.
    docs/install.md ("Checking a download") and SECURITY.md name the fingerprint of the key the
    artefacts on Maven Central are signed with, 39BA1E760ADE6940558B6EEC25FD2A2F5B520EB8, and say
    that the macOS executable is signed ad hoc and not notarised.
  • The base images of dist/Dockerfile and dist/Dockerfile.native are pinned by digest beside
    their tags, and Dependabot moves the digests; the image of a release names the base it was built on.
  • docs/cli.md names the veraPDF releases --verapdf should run — 1.30.2 or later, 1.31.71 or
    later on veraPDF's development line; earlier ones have advisories for untrusted PDFs — and caps
    its heap through JAVA_OPTS.
  • The workflows pin every action to a commit and keep no token in a checkout; the release and
    publish jobs build without a Maven cache. A release tag stops the release before anything is
    built unless it reads v1.2.3 or v1.2.3-rc.1 and names the version of the POM; publish.yml
    takes its tag only in that form and checks it out as a tag. Every push to main submits the
    resolved Maven dependency tree, so that Dependabot alerts cover the libraries the jar carries
    through other ones (fontbox, pdfbox-io, commons-logging, xmlresolver).

Format

  • SPEC.md section 9.5 names every character a finding message and a subject escape as \u
    and four lowercase hexadecimal digits: besides the C0 controls and DEL, every C1 control
    (U+0080–U+009F), U+2028, U+2029 and the bidirectional formatting characters, listed as
    U+061C, U+200E, U+200F, U+202A–U+202E and U+2066–U+2069. The reference implementation let the
    C1 controls and the two separators through, and U+061C in the messages of esj-core; the
    section said \uXXXX and left the case of the digits open.

Migration from 0.9.4

The API is cut before 1.0: what a caller is not meant to depend on moved into packages whose name
contains internal, and what may still change is marked @Preview. Neither is covered by the
compatibility promise. One row per package or type:

0.9.4 0.9.5
de.bsnsoft.esj.rules.en16931.En16931 de.bsnsoft.esj.rules.en16931.En16931Pack
de.bsnsoft.esj.rules.en16931.v2026.En16931V2026 de.bsnsoft.esj.rules.en16931.v2026.En16931V2026Pack, a preview; the service declaration of RulePackSource names it
de.bsnsoft.esj.rules.en16931.Br*, SchemeIdentifier de.bsnsoft.esj.rules.internal.en16931, internal
de.bsnsoft.esj.rules.en16931.v2026.Br* de.bsnsoft.esj.rules.internal.en16931.v2026, internal
"class" of javaRules in a rule pack manifest, …rules.en16931.Br62 …rules.internal.en16931.Br62; a manifest of a pack directory that names a rule of this build names it so
de.bsnsoft.esj.typed.runtime de.bsnsoft.esj.typed.internal, internal; generated views and the B2C overlay import it from there
de.bsnsoft.esj.xr.XmlFrontDoor de.bsnsoft.esj.xr.internal.XmlFrontDoor, internal
de.bsnsoft.esj.report (ValidationOutcome, Text, Phrase) de.bsnsoft.esj.internal.report, internal
de.bsnsoft.esj.render.ReportOptions de.bsnsoft.esj.render.internal.ReportOptions, internal
de.bsnsoft.esj.bindings.BindingTable no longer public; CiiWriter.semanticModel() and supports(String), UblWriter.semanticModel() and supports(String) say which edition a writer writes
esj-generator on Maven Central and in esj-bom not published; it is the build tool of this repository
de.bsnsoft.esj.xr.XrSyntax, de.bsnsoft.esj.bindings.BindingSyntax de.bsnsoft.esj.xml.InvoiceSyntax in esj-core; XmlFrontDoor.detect is InvoiceSyntax.of(namespace, localName) for a name
de.bsnsoft.esj.xr.XrEncodingMode de.bsnsoft.esj.xml.EncodingMode
de.bsnsoft.esj.xr.XmlEncodingReport de.bsnsoft.esj.xml.XmlEncodingReport
de.bsnsoft.esj.xr.XrEncodingException de.bsnsoft.esj.xml.XmlEncodingException, an EsjException and no XrException
de.bsnsoft.esj.xr.XmlBytes de.bsnsoft.esj.internal.XmlBytes, internal; XmlBytes.inspect(xml) is XmlEncodingReport.of(xml)
XrImporter.importXmlWithReport, importUblWithReport, importCiiWithReport, fromXrWithReport XrImporter.read, readUbl, readCii, readXr
XrImporter.importXml(xml), importUbl, importCii, fromXr XrImporter.read(xml).document(), readUbl, readCii, readXr
XrImporter.defaultRegistry() Registry.en16931WithXrechnung()
PdfInvoiceImporter.importPdf(pdf, XrImporter), importPdf(pdf, limits, XrImporter) importPdf(pdf, InvoiceReader), importPdf(pdf, limits, InvoiceReader); an XrImporter is one
PdfInvoiceImporter.importPdf(pdf) read with new XrImporter() reads with new StreamingReader(); importPdf(pdf, new XrImporter()) reads as before
XrLimitException, BindingLimitException, SyntaxLimitException, PdfLimitException, RenderLimitException de.bsnsoft.esj.EsjLimitException; bound() names the bound
SyntaxLimitException.budget() EsjLimitException.bound(), the bound maxRuntime in milliseconds
new RenderException(…) new RenderEngineException(…); RenderException is abstract
Esj.forMessage, Esj.forSubject, Esj.abbreviated de.bsnsoft.esj.internal.Messages, internal; Esj.steersATerminal and Esj.isBidiControl stay
Limits, PdfLimits, EmbedOptions, RenderOptions, TotalsOptions, AuthoringOptions (records), new X(…) final classes: X.defaults().withY(…)
Limits.builder()…build(), toBuilder(), Limits.Builder; the same for ReaderOptions, WriterOptions, UpgradeOptions X.defaults().withY(…), setter y(v) → withY(v)
UpgradeOptions.Builder.drop(path), extension(registry), source(bytes) withDroppable(paths), withExtensions(registries), withSource(bytes)
RenderOptions.in(language), .on(size), .with(template), .layout(layout) RenderOptions.defaults().withLanguage(language), .withPageSize(size), .withTemplate(template), .withLayout(layout)
RenderOptions.withPaymentCode(boolean), paymentCode() as Optional<Boolean> withPaymentCode(PaymentCode.DRAW / OMIT / TEMPLATE), paymentCode() as PaymentCode
EmbedOptions.of(profile), checkedWith(check) EmbedOptions.defaults().withProfile(profile), withCheck(check)
TotalsOptions.standard(), AuthoringOptions.standard() defaults()
DEFAULT_MAX_* of RenderOptions, PdfLimits, ReaderOptions, WriterOptions, SyntaxOptions; WriterOptions.DEFAULT_TAX_REGISTRATION_SCHEME, AuthoringOptions.DEFAULT_NET_PRICE_SCALE the accessor of defaults(), e.g. PdfLimits.defaults().maxPdfBytes(); RenderOptions.DEFAULT_LAYOUT stays
XrImporter.DEFAULT_MAX_INPUT_BYTES XrImporter.defaultMaxInputBytes()
Esj.VERSION, Esj.SEMANTIC_MODEL Esj.formatVersion(), Esj.defaultSemanticModel()
En16931Pack.VERSION, En16931Pack.EDITION, En16931V2026Pack.VERSION En16931Pack.version(), En16931Pack.edition(), En16931V2026Pack.version()
Rules.PACK_VERSION, B2cConsistency.PACK_VERSION Rules.packVersion(), B2cConsistency.packVersion()
Registry.DEFAULT_EDITION, Registry.editions() Registry.defaultEditionKey(), Registry.editionKeys()
RulePackSources.forEdition(registry.edition()) RulePackSources.forRegistry(registry)
de.bsnsoft.esj.syntax.Severity (FATAL, WARNING, INFORMATION), Severity.ofFlag de.bsnsoft.esj.validate.Severity (ERROR, WARNING, INFO)
de.bsnsoft.esj.rules.RuleSeverity (FATAL, WARNING, INFO), RuleSeverity.declared de.bsnsoft.esj.validate.Severity; JavaRule.severity() returns it
ContainerFinding.Severity de.bsnsoft.esj.validate.Severity
de.bsnsoft.esj.syntax.Verdict de.bsnsoft.esj.validate.ValidationStatus
Term (record), new Term(…) final class, made by Registry only
ExportResult, AttachmentContent (records), new …(…) final classes, made by the library only
de.bsnsoft.esj.render.ReportRenderer de.bsnsoft.esj.render.internal.ReportRenderer, internal
de.bsnsoft.esj.invoice.InvoiceSteps (interface) final class; its steps are sealed interfaces