JVM API¶
Built from main. The published release is 0.14.0.
This page describes 2ba20bd on main. The site deploys on every push; the package deploys on a tag.
Anything documented here that landed after 0.14.0 is not in the package you get from pip install disarm. The changelog says what is in which release, and releases is the tag list.
The surface of dev.disarm:disarm and dev.disarm:disarm-kotlin, and how it
lines up with the names used in the other bindings. For install, the JDK floor
and the bundled platforms, see Getting started.
This page covers what is specific to the JVM. Behaviour is language-neutral and lives once, in the concept and user-guide pages.
Two call styles¶
Disarm is a final class of static methods. disarm-kotlin adds top-level
extension functions over the same native core, so the choice is a matter of which
reads better in your codebase rather than which is capable.
| Java | Kotlin | |
|---|---|---|
| entry point | Disarm.transliterate(text) |
text.transliterate() |
| wide calls | options builders | default arguments |
| naming | camelCase |
camelCase |
| package | dev.disarm |
dev.disarm.kotlin for functions, dev.disarm for types |
Kotlin's functions are top-level. There is no Disarm object to call them on,
and getPipeline is a top-level function too.
import dev.disarm.TargetScript // types
import dev.disarm.kotlin.* // functions
What the JVM surface does not have¶
Measured against the 86 canonical operations in generated/parity.yaml, the JVM
covers 50. Some of the remainder are deprecated aliases or Python-only
conveniences and are not gaps at all. These are the ones that are:
| absent | what it is | reach it with |
|---|---|---|
canonicalizeStrict |
the stricter comparison preset | canonicalize, then screen separately |
stripFormat |
strip bidi and invisibles, keep the script | canonicalize (also folds confusables) |
escapeHtml, percentEncode |
output encoders | your framework's encoder, which you should prefer anyway |
stripLogInjection |
neutralize a log line | canonicalize plus your own newline handling |
decodeToUtf8, detectEncoding |
encoding recovery | — |
listLangs, listProfiles, reverseLangs |
introspection | — |
registerLang, registerReplacements |
runtime registration | — |
setEmojiProvider |
custom emoji naming | — |
isAscii |
a predicate | text.chars().allMatch(c -> c < 128) |
canonicalizeStrict is the one to know about.
CVE Validation measures that
canonicalize_strict and strip_obfuscation are the two presets that clear every
row of the matrix, and recommends them on that basis. On the JVM only
stripObfuscation exists, so the two-call advice cannot be followed as written.
stripObfuscation alone clears the matrix; canonicalize misses the eclipsing
mark in CVE-2017-7833.
The JVM is also absent from the parity matrix itself, which tracks rust, python, ruby and node. The coverage figure above was measured for this page rather than read off a gate, so treat it as accurate on the day it was written rather than maintained. Both halves are tracked in #677.
Options builders¶
Four, all with the same shape: a static builder(), chained setters, and
build().
TransliterateOptions.builder().scheme(Scheme.STRICT_ISO9).lang("ru").build();
SlugOptions.builder()
.separator("_").lowercase(true).maxLength(64)
.wordBoundary(true).saveOrder(true).stopwords(List.of("the"))
.allowUnicode(false).lang("de")
.build();
SanitizeFilenameOptions.builder()
.separator("_").maxLength(255).platform(Platform.WINDOWS)
.lang("de").preserveExtension(true)
.build();
MlNormalizeOptions.builder().lang("de").emojiStyle("cldr").foldCase(false).build();
Kotlin passes the same values as named arguments and does not use the builders.
Types¶
| type | what it carries |
|---|---|
AnomalyReport |
anomalous, kinds, findings, reason |
Finding |
one anomaly: kind, token, start, end, detail, reason |
HostnameAnalysis |
suspicious, canonical, scripts, mixedScript, hasConfusables, bidiConflict, bidiControl, hasInvisible, crossLabelScript, labelScripts, wholeScriptConfusable, labelWholeScriptConfusable |
KeyCollision |
key, values, indices |
UnmappedConfusable, Untranslatable |
coverage residue |
LangMeta, ScriptMeta, AutoLangInspection |
metadata |
Lexicon, Pipeline |
native handles, AutoCloseable |
TargetScript, NormalizationForm, DigitPolicy, Platform |
enums |
Scheme |
nested in TransliterateOptions; Kotlin aliases it as Scheme |
Name mapping¶
The other bindings use snake_case; the JVM uses camelCase. Everything else is
the same name, with three exceptions worth knowing:
| elsewhere | JVM |
|---|---|
is_suspicious_hostname → (bool, analysis) in Python |
isSuspiciousHostname → boolean, and analyzeHostname → HostnameAnalysis |
has_anomalies(text) |
hasAnomalies(text, words) — no single-argument form |
Disarm.canonicalize(...) in Java |
"...".canonicalize() in Kotlin |
The hostname split is the one that catches people. Python returns the verdict and
the analysis together; the JVM has a predicate and a separate analysis call, so
asking for both means two calls or one call to analyzeHostname and reading
.suspicious() off it.
Errors¶
DisarmException (extends RuntimeException)
└── DisarmInvalidArgumentException
Unchecked, so nothing forces a try. DisarmInvalidArgumentException is thrown
for a value the library can name as wrong (an unknown profile, an unsupported
scheme) and carries the offending value and the valid set in its message.
Signature stability (#588)¶
Every public Kotlin function with a default argument carries @JvmOverloads, so
each default emits a real JVM method instead of a synthetic $default bridge.
Without it, adding a default to a shipped function deletes an arity that existed,
and callers who have not recompiled meet a NoSuchMethodError at run time.
JvmSignatureTest pins the arities in CI. See
BINDINGS.md for why this is a
guarantee rather than a style.