Serialization in Tika 4.x

The JSON serialization design behind Tika 4.x configuration. For the API you actually call, see Serialization and Configuration; for the wider 4.x architecture, see Design Notes for 4.x.

Design Goals

Jackson, minimally wrapped

Use Jackson as much as possible, with as few custom serializers and annotations as possible. Jackson dependencies stay out of the core modules so those modules remain free of it.

Friendly names, not class names

Configuration refers to components by friendly names such as pdf-parser. The name belongs to the configured item, not to a configuration class.

Custom classes via @TikaComponent, not polymorphic typing

Annotate a class with @TikaComponent and the annotation processor generates a META-INF/tika/*.idx registry entry at compile time. Any class whose .idx entry is on the classpath can then be named in JSON. Unregistered classes and packages cannot be instantiated — there is no package-pattern allowlist and no Class.forName fallback.

The same shape at init and at runtime

Initialization and runtime configuration should look identical and share the same underlying code. Security constraints may still restrict which fields are modifiable at runtime.

Config objects, not field annotations

Configuration lives in config objects rather than annotated parser fields, so parsers stay usable from multiple threads; a parser reads its settings from ParseContext at parse time.

One config format across systems

The same configuration passes from a user’s client, through the tika-server REST API, into the tika-pipes infrastructure, without translation at each hop.

Discovering the friendly name for a component

The 4.x JSON config refers to parsers, detectors, fetchers, emitters, and other components by their friendly name (e.g., pdf-parser, file-system-fetcher). To map a Java class to its friendly name (or vice versa), use any of:

  1. tika-app --list-parser-names / --list-detector-names — emits each registered class with its friendly name as tab-separated class<TAB>friendly-name:

    java -jar tika-app.jar --list-parser-names
    # org.apache.tika.parser.pdf.PDFParser     pdf-parser
    # org.apache.tika.parser.html.JSoupParser  jsoup-parser
    # ...

    The mapping comes from the META-INF/tika/parsers.idx / detectors.idx files generated at compile time by the @TikaComponent annotation processor. The underlying lookup is o.a.t.config.loader.ComponentRegistry.getFriendlyName(Class).

  2. Per-parser configuration pages under Configuration show the friendly name in their page title and JSON examples.

  3. The naming convention — when @TikaComponent has no explicit name, the friendly name is derived from the class’s simple name via the kebab-case rule in o.a.t.config.loader.KebabCaseConverter. Examples:

    Class Friendly name

    PDFParser

    pdf-parser

    TesseractOCRParser

    tesseract-ocr-parser

    AutoDetectParser

    auto-detect-parser

    FileSystemFetcher

    file-system-fetcher

    SolrEmitter

    solr-emitter

The --list-parsers, --list-detectors, and --list-parser-details commands print the hierarchical, human-oriented view (class names with composite parsers indented). Use the --list-*-names variants when you want a machine-readable mapping.

Initialization Structure

Tier 1 — the top-level config sections, each loaded into a component of a known kind:

ID objects

Fetchers and emitters — components addressed by a unique identifier.

Composite objects

Parsers and detectors — components that aggregate other components.

Single objects

The pipes, grpc, and server configurations.

Tier 2 — anything else that carries @TikaComponent, bound by friendly name inside the parse-context section.

Runtime Patterns

Backwards compatibility

New capabilities are added to ParseContext, keyed by their interface, so an existing context keeps working.

Partial configuration updates

A partial JSON object may specify only the updates to the initialization configuration; a complete configuration document is not required.

Self-configuring components in pipes

In the pipes infrastructure, components configure themselves rather than being configured by a central loader, so nothing has to load classes like PDFParser to configure them.

Security Model

Configuration files read at initialization are treated as trusted sources. Component instantiation from JSON is restricted to classes registered at compile time by the @TikaComponent annotation processor (META-INF/tika/*.idx files); unknown class names are rejected, and there is no Jackson default typing.

Untrusted per-request configuration (tika-server requests, pipes FetchEmitTuple`s) is deserialized in a restricted mode that additionally applies a fail-closed allowlist of context-key types: only metadata/output-shaping components (e.g. `MetadataFilter, ContentHandlerFactory, DigesterFactory) may be bound from the wire; Parser, Detector, Renderer, and similar are blocked before anything is constructed.

Note the boundary: the allowlist blocks binding a component from the wire, not configuring one that is already loaded. Self-configuring components — every Parser among them — have their config subtree passed through unscanned, so a per-request config can still set parser options (including ones that spawn external processes, such as OCR). This is why allowPerRequestConfig is a separate gate and is off by default; the allowlist alone does not make per-request configuration safe to expose.