Author: tallison
Date: Sat Aug 22 01:56:19 2026
New Revision: 1937303

Log:
4.0.0 docs: 4.0.x developers

Added:
   tika/site/publish/docs/4.0.x/developers/
   tika/site/publish/docs/4.0.x/developers/index.html
   tika/site/publish/docs/4.0.x/developers/metadata-keys.html
   tika/site/publish/docs/4.0.x/developers/serialization.html

Added: tika/site/publish/docs/4.0.x/developers/index.html
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ tika/site/publish/docs/4.0.x/developers/index.html  Sat Aug 22 01:56:19 
2026        (r1937303)
@@ -0,0 +1,456 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1">
+    <title>Developer Guide :: Apache Tika Documentation</title>
+    <link rel="canonical" 
href="https://tika.apache.org/docs/tika/4.0.x/developers/index.html";>
+    <meta name="generator" content="Antora 3.1.15">
+    <link rel="stylesheet" href="../../../_/css/site.css">
+  </head>
+  <body class="article">
+<header class="header">
+  <nav class="navbar" aria-label="Main">
+    <div class="navbar-brand">
+      <a class="navbar-item" href="../../..">
+        <img src="../../../_/img/ASF_Tika-colour.svg" alt="Apache Tika" 
style="height: 2rem; margin-right: 0.5rem; background: white; padding: 2px 4px; 
border-radius: 3px;">
+        Apache Tika Documentation
+      </a>
+      <div class="navbar-item search hide-for-print" role="search">
+        <div id="search-field" class="field">
+          <input id="search-input" type="search" aria-label="Search the docs" 
placeholder="Search the docs">
+        </div>
+      </div>
+      <button class="navbar-burger" aria-controls="topbar-nav" 
aria-expanded="false" aria-label="Toggle main menu" data-target="topbar-nav">
+        <span></span>
+        <span></span>
+        <span></span>
+      </button>
+    </div>
+    <div id="topbar-nav" class="navbar-menu">
+      <div class="navbar-end">
+        <a class="navbar-item" href="https://tika.apache.org";>Apache Tika</a>
+        <a class="navbar-item" href="https://github.com/apache/tika";>GitHub</a>
+      </div>
+    </div>
+  </nav>
+</header>
+<div class="body">
+<div class="nav-container" data-component="tika" data-version="4.0.x">
+  <aside class="nav">
+    <div class="panels">
+<div class="nav-panel-menu is-active" data-panel="menu">
+  <nav class="nav-menu">
+    <button class="nav-menu-toggle" aria-label="Toggle expand/collapse all" 
style="display: none"></button>
+    <h3 class="title"><a href="../index.html">Apache Tika</a></h3>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="0">
+<ul class="nav-list">
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../index.html">Home</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/index.html">Using Tika</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/java-api/index.html">Java API</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../using-tika/java-api/getting-started.html">Getting Started with the 
Java API</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/cli/index.html">Command Line</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/server/index.html">Tika Server</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../using-tika/server/tls.html">TLS/SSL 
Configuration</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/grpc/index.html">gRPC</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/docker.html">Running Tika in 
Docker</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/index.html">Pipes</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/getting-started.html">Getting 
Started</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/configuration.html">Pipeline 
Configuration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/fetchers.html">Fetchers</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/emitters.html">Emitters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/iterators.html">Iterators</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/reporters.html">Reporters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/parse-modes.html">Parse Modes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/unpack-config.html">Extracting Embedded 
Bytes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/timeouts.html">Timeouts</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/cpu-sizing.html">Forked-JVM CPU and 
Heap Sizing</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/shared-server-mode.html">Shared Server 
Mode</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/performance.html">Performance and 
Isolation Trade-offs</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../pipes/troubleshooting.html">Troubleshooting</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/plugins/index.html">Plugins</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/writing-a-plugin.html">Writing 
a Pipes Plugin</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/filesystem.html">File System</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/s3.html">Amazon S3</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/gcs.html">Google Cloud 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/azblob.html">Azure Blob 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/opensearch.html">OpenSearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../pipes/plugins/elasticsearch.html">Elasticsearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/solr.html">Apache Solr</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/jdbc.html">JDBC</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/kafka.html">Apache Kafka</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/http.html">HTTP</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/google-drive.html">Google 
Drive</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/microsoft-graph.html">Microsoft 
Graph</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/atlassian-jwt.html">Atlassian 
JWT</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/csv.html">CSV</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/json.html">JSON</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../configuration/index.html">Configuration</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/pdf-parser.html">PDF 
Parser</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tesseract-ocr-parser.html">Tesseract OCR</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/vlm-parsers.html">VLM 
Parsers (Claude, Gemini, OpenAI)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/external-parser.html">External Parser (ffmpeg, 
exiftool, etc.)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tess4j-parser.html">Tess4J OCR (In-Process, 
advanced)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/metadata-filters.html">Metadata 
Filters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/detectors.html">Detectors</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/digesters.html">Digesters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/encoding-detectors.html">Encoding Detectors</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../migration-to-4x/index.html">Migration to 
4.x</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-to-4x.html">Migration Guide</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-tika-server-4x.html">Tika Server 
Migration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/serialization-4x.html">Serialization Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/metadata-changes-4x.html">Metadata Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/design-notes-4x.html">Design 
Notes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/chunk-strategies.html">Chunk 
Strategies</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/inference-handler-requirements.html">Inference Handler 
Requirements</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../advanced/index.html">Advanced</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/robustness.html">Robustness</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/setting-limits.html">Setting 
Limits</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/spooling.html">TikaInputStream and 
Spooling</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/language-detection.html">Language 
Detection</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/language-detection-build.html">Building the Language 
Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charsoup-supported-languages.html">CharSoup Supported 
Languages</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection.html">Text Quality 
Scoring (Junk Detection)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection-build.html">Building 
the Junk Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charset-detection-design.html">Charset Detection Pipeline</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/zip-detection.html">ZIP Detection 
and Salvaging</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/embedded-documents.html">Embedded 
Document Metadata</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/local-vlm-server.html">Running a 
Local VLM Server</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <span class="nav-text">Integration Testing</span>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-app.html">Testing with Tika App</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-server.html">Testing with Tika 
Server</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/run-uat-script.html">Tika-Server REST UAT 
Script</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-eval-regression.html">Regression 
Evaluation with tika-eval</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../security.html">Security</a>
+  </li>
+  <li class="nav-item is-current-page" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="index.html">Developers</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="serialization.html">Serialization and 
Configuration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="metadata-keys.html">Adding a Metadata Key</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../faq.html">FAQ</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../roadmap.html">Roadmap</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../maintainers/index.html">Maintainers</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../maintainers/site.html">Publishing the Site</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" 
href="../maintainers/release-guides/index.html">Release Guides</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/tika.html">Releasing Apache Tika</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/release-artifacts.html">Release Artifacts: 
What Goes Where</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/docker.html">Releasing Tika Docker 
Images</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/helm.html">Releasing Tika Helm Charts</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/grpc.html">Releasing Tika gRPC</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </nav>
+</div>
+<div class="nav-panel-explore" data-panel="explore">
+  <div class="context">
+    <span class="title">Apache Tika</span>
+    <span class="version">4.0.x</span>
+  </div>
+  <ul class="components">
+    <li class="component is-current">
+      <div class="title"><a href="../index.html">Apache Tika</a></div>
+      <ul class="versions">
+        <li class="version">
+          <a href="../../4.0.1-SNAPSHOT/index.html">4.0.1-SNAPSHOT</a>
+        </li>
+        <li class="version is-current is-latest">
+          <a href="../index.html">4.0.x</a>
+        </li>
+      </ul>
+    </li>
+  </ul>
+</div>
+    </div>
+  </aside>
+</div>
+<main class="article">
+<div class="toolbar" role="navigation" aria-label="Page tools">
+<button class="nav-toggle" aria-label="Toggle navigation"></button>
+</div>
+  <div class="content">
+<aside class="toc sidebar" data-title="Contents" data-levels="2">
+  <div class="toc-menu"></div>
+</aside>
+<article class="doc">
+<h1 class="page">Developer Guide</h1>
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_topics">Topics</a></li>
+<li><a href="#_coming_soon">Coming Soon</a></li>
+</ul>
+</div>
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>This section provides documentation for developers who want to extend Tika
+with custom parsers, detectors, and other components.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_topics"><a class="anchor" href="#_topics"></a>Topics</h2>
+<div class="sectionbody">
+<div class="ulist">
+<ul>
+<li>
+<p><a href="serialization.html" class="xref page">Serialization and 
Configuration</a> - JSON configuration,
+@TikaComponent annotation, and creating custom components</p>
+</li>
+<li>
+<p><a href="metadata-keys.html" class="xref page">Adding a Metadata Key</a> - 
the Property/KeyPrefix
+registry, naming conventions, and regenerating the schema</p>
+</li>
+<li>
+<p><a href="../pipes/plugins/writing-a-plugin.html" class="xref page">Writing 
a Pipes Plugin</a> - implementing a fetcher,
+emitter, iterator or reporter and packaging it for PF4J</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_coming_soon"><a class="anchor" href="#_coming_soon"></a>Coming 
Soon</h2>
+<div class="sectionbody">
+<div class="ulist">
+<ul>
+<li>
+<p>Creating Custom Parsers</p>
+</li>
+<li>
+<p>Creating Custom Detectors</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</article>
+  </div>
+</main>
+</div>
+<footer class="footer">
+  <p>© Apache Software Foundation. All rights reserved.</p>
+</footer>
+<script id="site-script" src="../../../_/js/site.js" 
data-ui-root-path="../../../_"></script>
+<script async src="../../../_/js/vendor/highlight.js"></script>
+<script src="../../../_/js/vendor/lunr.js"></script>
+<script src="../../../_/js/search-ui.js" id="search-ui-script" 
data-site-root-path="../../.." data-snippet-length="150" 
data-stylesheet="../../../_/css/search.css"></script>
+<script async src="../../../search-index.js"></script>
+  </body>
+</html>

Added: tika/site/publish/docs/4.0.x/developers/metadata-keys.html
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ tika/site/publish/docs/4.0.x/developers/metadata-keys.html  Sat Aug 22 
01:56:19 2026        (r1937303)
@@ -0,0 +1,536 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1">
+    <title>Adding a Metadata Key :: Apache Tika Documentation</title>
+    <link rel="canonical" 
href="https://tika.apache.org/docs/tika/4.0.x/developers/metadata-keys.html";>
+    <meta name="generator" content="Antora 3.1.15">
+    <link rel="stylesheet" href="../../../_/css/site.css">
+  </head>
+  <body class="article">
+<header class="header">
+  <nav class="navbar" aria-label="Main">
+    <div class="navbar-brand">
+      <a class="navbar-item" href="../../..">
+        <img src="../../../_/img/ASF_Tika-colour.svg" alt="Apache Tika" 
style="height: 2rem; margin-right: 0.5rem; background: white; padding: 2px 4px; 
border-radius: 3px;">
+        Apache Tika Documentation
+      </a>
+      <div class="navbar-item search hide-for-print" role="search">
+        <div id="search-field" class="field">
+          <input id="search-input" type="search" aria-label="Search the docs" 
placeholder="Search the docs">
+        </div>
+      </div>
+      <button class="navbar-burger" aria-controls="topbar-nav" 
aria-expanded="false" aria-label="Toggle main menu" data-target="topbar-nav">
+        <span></span>
+        <span></span>
+        <span></span>
+      </button>
+    </div>
+    <div id="topbar-nav" class="navbar-menu">
+      <div class="navbar-end">
+        <a class="navbar-item" href="https://tika.apache.org";>Apache Tika</a>
+        <a class="navbar-item" href="https://github.com/apache/tika";>GitHub</a>
+      </div>
+    </div>
+  </nav>
+</header>
+<div class="body">
+<div class="nav-container" data-component="tika" data-version="4.0.x">
+  <aside class="nav">
+    <div class="panels">
+<div class="nav-panel-menu is-active" data-panel="menu">
+  <nav class="nav-menu">
+    <button class="nav-menu-toggle" aria-label="Toggle expand/collapse all" 
style="display: none"></button>
+    <h3 class="title"><a href="../index.html">Apache Tika</a></h3>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="0">
+<ul class="nav-list">
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../index.html">Home</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/index.html">Using Tika</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/java-api/index.html">Java API</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../using-tika/java-api/getting-started.html">Getting Started with the 
Java API</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/cli/index.html">Command Line</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/server/index.html">Tika Server</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../using-tika/server/tls.html">TLS/SSL 
Configuration</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/grpc/index.html">gRPC</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/docker.html">Running Tika in 
Docker</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/index.html">Pipes</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/getting-started.html">Getting 
Started</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/configuration.html">Pipeline 
Configuration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/fetchers.html">Fetchers</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/emitters.html">Emitters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/iterators.html">Iterators</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/reporters.html">Reporters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/parse-modes.html">Parse Modes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/unpack-config.html">Extracting Embedded 
Bytes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/timeouts.html">Timeouts</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/cpu-sizing.html">Forked-JVM CPU and 
Heap Sizing</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/shared-server-mode.html">Shared Server 
Mode</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/performance.html">Performance and 
Isolation Trade-offs</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../pipes/troubleshooting.html">Troubleshooting</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/plugins/index.html">Plugins</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/writing-a-plugin.html">Writing 
a Pipes Plugin</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/filesystem.html">File System</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/s3.html">Amazon S3</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/gcs.html">Google Cloud 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/azblob.html">Azure Blob 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/opensearch.html">OpenSearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../pipes/plugins/elasticsearch.html">Elasticsearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/solr.html">Apache Solr</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/jdbc.html">JDBC</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/kafka.html">Apache Kafka</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/http.html">HTTP</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/google-drive.html">Google 
Drive</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/microsoft-graph.html">Microsoft 
Graph</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/atlassian-jwt.html">Atlassian 
JWT</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/csv.html">CSV</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/json.html">JSON</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../configuration/index.html">Configuration</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/pdf-parser.html">PDF 
Parser</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tesseract-ocr-parser.html">Tesseract OCR</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/vlm-parsers.html">VLM 
Parsers (Claude, Gemini, OpenAI)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/external-parser.html">External Parser (ffmpeg, 
exiftool, etc.)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tess4j-parser.html">Tess4J OCR (In-Process, 
advanced)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/metadata-filters.html">Metadata 
Filters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/detectors.html">Detectors</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/digesters.html">Digesters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/encoding-detectors.html">Encoding Detectors</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../migration-to-4x/index.html">Migration to 
4.x</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-to-4x.html">Migration Guide</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-tika-server-4x.html">Tika Server 
Migration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/serialization-4x.html">Serialization Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/metadata-changes-4x.html">Metadata Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/design-notes-4x.html">Design 
Notes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/chunk-strategies.html">Chunk 
Strategies</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/inference-handler-requirements.html">Inference Handler 
Requirements</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../advanced/index.html">Advanced</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/robustness.html">Robustness</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/setting-limits.html">Setting 
Limits</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/spooling.html">TikaInputStream and 
Spooling</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/language-detection.html">Language 
Detection</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/language-detection-build.html">Building the Language 
Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charsoup-supported-languages.html">CharSoup Supported 
Languages</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection.html">Text Quality 
Scoring (Junk Detection)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection-build.html">Building 
the Junk Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charset-detection-design.html">Charset Detection Pipeline</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/zip-detection.html">ZIP Detection 
and Salvaging</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/embedded-documents.html">Embedded 
Document Metadata</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/local-vlm-server.html">Running a 
Local VLM Server</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <span class="nav-text">Integration Testing</span>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-app.html">Testing with Tika App</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-server.html">Testing with Tika 
Server</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/run-uat-script.html">Tika-Server REST UAT 
Script</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-eval-regression.html">Regression 
Evaluation with tika-eval</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../security.html">Security</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="index.html">Developers</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="serialization.html">Serialization and 
Configuration</a>
+  </li>
+  <li class="nav-item is-current-page" data-depth="2">
+    <a class="nav-link" href="metadata-keys.html">Adding a Metadata Key</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../faq.html">FAQ</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../roadmap.html">Roadmap</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../maintainers/index.html">Maintainers</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../maintainers/site.html">Publishing the Site</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" 
href="../maintainers/release-guides/index.html">Release Guides</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/tika.html">Releasing Apache Tika</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/release-artifacts.html">Release Artifacts: 
What Goes Where</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/docker.html">Releasing Tika Docker 
Images</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/helm.html">Releasing Tika Helm Charts</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/grpc.html">Releasing Tika gRPC</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </nav>
+</div>
+<div class="nav-panel-explore" data-panel="explore">
+  <div class="context">
+    <span class="title">Apache Tika</span>
+    <span class="version">4.0.x</span>
+  </div>
+  <ul class="components">
+    <li class="component is-current">
+      <div class="title"><a href="../index.html">Apache Tika</a></div>
+      <ul class="versions">
+        <li class="version">
+          <a href="../../4.0.1-SNAPSHOT/index.html">4.0.1-SNAPSHOT</a>
+        </li>
+        <li class="version is-current is-latest">
+          <a href="../index.html">4.0.x</a>
+        </li>
+      </ul>
+    </li>
+  </ul>
+</div>
+    </div>
+  </aside>
+</div>
+<main class="article">
+<div class="toolbar" role="navigation" aria-label="Page tools">
+<button class="nav-toggle" aria-label="Toggle navigation"></button>
+</div>
+  <div class="content">
+<aside class="toc sidebar" data-title="Contents" data-levels="2">
+  <div class="toc-menu"></div>
+</aside>
+<article class="doc">
+<h1 class="page">Adding a Metadata Key</h1>
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_add_the_constant">Add the constant</a></li>
+<li><a href="#_document_derived_names_declare_a_keyprefix">Document-derived 
names: declare a KeyPrefix</a></li>
+<li><a href="#_regenerate_the_registry">Regenerate the registry</a></li>
+<li><a href="#_after_a_rename">After a rename</a></li>
+</ul>
+</div>
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>Every metadata key Tika can emit is a <code>Property</code> constant (or, 
for runtime-minted names like scraped
+HTML <code>&lt;meta&gt;</code> tags, a <code>KeyPrefix</code>) — there are no 
bare <code>String</code> keys naming a population of writable
+metadata. (One <code>String</code> constant remains as an exception: 
<code>TikaCoreProperties.EMBEDDED_RESOURCE_TYPE_KEY</code>
+is an internal building block that constructs the <code>Property</code> name 
for <code>EMBEDDED_RESOURCE_TYPE</code> — not an
+independent key — and is excluded from the registry&#8217;s key count for that 
reason.) That closed/open key
+space is tracked in a generated, build-gated registry, so adding a key 
involves one extra step beyond
+writing the Java.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_add_the_constant"><a class="anchor" href="#_add_the_constant"></a>Add 
the constant</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>A curated <code>tk:</code> key can only be minted from inside 
<code>org.apache.tika.metadata</code>, via the
+package-private <code>reserved*</code> factories&#8201;&#8212;&#8201;a public 
<code>Property</code> factory rejects a <code>tk:</code>/<code>X-TIKA:</code>
+name at construction time. Add it to <code>TikaCoreProperties</code> (or 
another class in that package)
+as usual:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">Property MY_NEW_KEY = 
Property.reservedInternalText(TIKA_META_PREFIX + "my-new-key");</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>A parser module coining its own key uses a public factory in its own 
namespace instead:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">Property MY_NEW_KEY = 
Property.internalText("myformat:my-new-key");</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Naming conventions (frozen for 4.0):</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Tika-coined keys use the <code>tk:</code> namespace, kebab-case, no 
underscores.</p>
+</li>
+<li>
+<p>External-standard names are used verbatim, including the standard&#8217;s 
own prefix (<code>dc:</code>, <code>xmp:</code>,
+<code>cp:</code>, <code>extended-properties:</code>).</p>
+</li>
+<li>
+<p>HTTP headers stay bare — no <code>http:</code> namespace 
(<code>Content-Type</code>, <code>Content-Encoding</code>, 
<code>Location</code>).</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_document_derived_names_declare_a_keyprefix"><a class="anchor" 
href="#_document_derived_names_declare_a_keyprefix"></a>Document-derived names: 
declare a KeyPrefix</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>When the key <strong>names</strong> come from the document or an external 
tool (custom document properties,
+format-specific attribute names, NER labels), they can&#8217;t be constants. 
Declare a <code>KeyPrefix</code>
+once, as a <code>static final</code> field — never per-parse, never from 
document text — and write through
+<code>Metadata#add(KeyPrefix, String, String)</code>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">static final KeyPrefix MYFORMAT = KeyPrefix.file("myformat:", 
"myformat's own header fields");
+...
+metadata.add(MYFORMAT, nameFromDocument, value);              // String value
+metadata.add(MYFORMAT, nameFromDocument, date.toInstant());   // source-typed 
date</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The route is append-only (repeated names accumulate, losslessly 
transcribing the source) and
+never throws on hostile input: blank, over-length, or flooding names are 
skipped with a WARN.
+Use <code>KeyPrefix.file(&#8230;&#8203;)</code> for names read out of the 
document, <code>KeyPrefix.tool(&#8230;&#8203;)</code> for names
+coined by an external tool or service.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_regenerate_the_registry"><a class="anchor" 
href="#_regenerate_the_registry"></a>Regenerate the registry</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The registry — three JSON files under
+<code>tika-metadata-schema/src/main/resources/org/apache/tika/metadata/</code>,
 listing every
+declared key, every open-namespace prefix, and a field-provenance table — is 
generated from the live
+<code>Property</code>/<code>KeyPrefix</code> declarations, never hand-edited. 
A committed copy is the reviewable
+audit trail (a rename or dropped key shows up as a diff), and CI fails if 
it&#8217;s stale.</p>
+</div>
+<div class="paragraph">
+<p>Run this after adding, renaming, or removing a <code>Property</code> or 
<code>KeyPrefix</code>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-bash hljs" 
data-lang="bash">tika-metadata-schema/regen.sh</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It installs the modules the change touched, regenerates all three registry 
files, sanity-checks the
+diff, and runs the gate tests. Commit the Java change and the regenerated JSON 
together.</p>
+</div>
+<div class="paragraph">
+<p>Flags are on <code>regen.sh --help</code>. The registry design is in 
<code>tika-metadata-schema/README.md</code>;
+the traps this script routes around (classpath scanning quirks, 
<code>exec:java</code> vs. a forked
+classpath) are in <code>.skills/metadata-schema/SKILL.md</code>.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_after_a_rename"><a class="anchor" href="#_after_a_rename"></a>After a 
rename</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The compiler won&#8217;t catch a stale string literal like 
<code>metadata.get("Message-From")</code>. Grep the repo
+for the old key and replace it with the constant:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-bash hljs" 
data-lang="bash">grep -rn '"Message-' --include=*.java . | grep -v 
/target/</code></pre>
+</div>
+</div>
+</div>
+</div>
+</article>
+  </div>
+</main>
+</div>
+<footer class="footer">
+  <p>© Apache Software Foundation. All rights reserved.</p>
+</footer>
+<script id="site-script" src="../../../_/js/site.js" 
data-ui-root-path="../../../_"></script>
+<script async src="../../../_/js/vendor/highlight.js"></script>
+<script src="../../../_/js/vendor/lunr.js"></script>
+<script src="../../../_/js/search-ui.js" id="search-ui-script" 
data-site-root-path="../../.." data-snippet-length="150" 
data-stylesheet="../../../_/css/search.css"></script>
+<script async src="../../../search-index.js"></script>
+  </body>
+</html>

Added: tika/site/publish/docs/4.0.x/developers/serialization.html
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ tika/site/publish/docs/4.0.x/developers/serialization.html  Sat Aug 22 
01:56:19 2026        (r1937303)
@@ -0,0 +1,1096 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1">
+    <title>Serialization and Configuration :: Apache Tika Documentation</title>
+    <link rel="canonical" 
href="https://tika.apache.org/docs/tika/4.0.x/developers/serialization.html";>
+    <meta name="generator" content="Antora 3.1.15">
+    <link rel="stylesheet" href="../../../_/css/site.css">
+  </head>
+  <body class="article">
+<header class="header">
+  <nav class="navbar" aria-label="Main">
+    <div class="navbar-brand">
+      <a class="navbar-item" href="../../..">
+        <img src="../../../_/img/ASF_Tika-colour.svg" alt="Apache Tika" 
style="height: 2rem; margin-right: 0.5rem; background: white; padding: 2px 4px; 
border-radius: 3px;">
+        Apache Tika Documentation
+      </a>
+      <div class="navbar-item search hide-for-print" role="search">
+        <div id="search-field" class="field">
+          <input id="search-input" type="search" aria-label="Search the docs" 
placeholder="Search the docs">
+        </div>
+      </div>
+      <button class="navbar-burger" aria-controls="topbar-nav" 
aria-expanded="false" aria-label="Toggle main menu" data-target="topbar-nav">
+        <span></span>
+        <span></span>
+        <span></span>
+      </button>
+    </div>
+    <div id="topbar-nav" class="navbar-menu">
+      <div class="navbar-end">
+        <a class="navbar-item" href="https://tika.apache.org";>Apache Tika</a>
+        <a class="navbar-item" href="https://github.com/apache/tika";>GitHub</a>
+      </div>
+    </div>
+  </nav>
+</header>
+<div class="body">
+<div class="nav-container" data-component="tika" data-version="4.0.x">
+  <aside class="nav">
+    <div class="panels">
+<div class="nav-panel-menu is-active" data-panel="menu">
+  <nav class="nav-menu">
+    <button class="nav-menu-toggle" aria-label="Toggle expand/collapse all" 
style="display: none"></button>
+    <h3 class="title"><a href="../index.html">Apache Tika</a></h3>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="0">
+<ul class="nav-list">
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../index.html">Home</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/index.html">Using Tika</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/java-api/index.html">Java API</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../using-tika/java-api/getting-started.html">Getting Started with the 
Java API</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/cli/index.html">Command Line</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../using-tika/server/index.html">Tika Server</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../using-tika/server/tls.html">TLS/SSL 
Configuration</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/grpc/index.html">gRPC</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../using-tika/docker.html">Running Tika in 
Docker</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/index.html">Pipes</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/getting-started.html">Getting 
Started</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/configuration.html">Pipeline 
Configuration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/fetchers.html">Fetchers</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/emitters.html">Emitters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/iterators.html">Iterators</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/reporters.html">Reporters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/parse-modes.html">Parse Modes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/unpack-config.html">Extracting Embedded 
Bytes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/timeouts.html">Timeouts</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/cpu-sizing.html">Forked-JVM CPU and 
Heap Sizing</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/shared-server-mode.html">Shared Server 
Mode</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../pipes/performance.html">Performance and 
Isolation Trade-offs</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../pipes/troubleshooting.html">Troubleshooting</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../pipes/plugins/index.html">Plugins</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/writing-a-plugin.html">Writing 
a Pipes Plugin</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/filesystem.html">File System</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/s3.html">Amazon S3</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/gcs.html">Google Cloud 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/azblob.html">Azure Blob 
Storage</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/opensearch.html">OpenSearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../pipes/plugins/elasticsearch.html">Elasticsearch</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/solr.html">Apache Solr</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/jdbc.html">JDBC</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/kafka.html">Apache Kafka</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/http.html">HTTP</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/google-drive.html">Google 
Drive</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/microsoft-graph.html">Microsoft 
Graph</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/atlassian-jwt.html">Atlassian 
JWT</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/csv.html">CSV</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" href="../pipes/plugins/json.html">JSON</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../configuration/index.html">Configuration</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/pdf-parser.html">PDF 
Parser</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tesseract-ocr-parser.html">Tesseract OCR</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/parsers/vlm-parsers.html">VLM 
Parsers (Claude, Gemini, OpenAI)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/external-parser.html">External Parser (ffmpeg, 
exiftool, etc.)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/parsers/tess4j-parser.html">Tess4J OCR (In-Process, 
advanced)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/metadata-filters.html">Metadata 
Filters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/detectors.html">Detectors</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../configuration/digesters.html">Digesters</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../configuration/encoding-detectors.html">Encoding Detectors</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../migration-to-4x/index.html">Migration to 
4.x</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-to-4x.html">Migration Guide</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/migrating-tika-server-4x.html">Tika Server 
Migration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/serialization-4x.html">Serialization Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/metadata-changes-4x.html">Metadata Changes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/design-notes-4x.html">Design 
Notes</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../migration-to-4x/chunk-strategies.html">Chunk 
Strategies</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../migration-to-4x/inference-handler-requirements.html">Inference Handler 
Requirements</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../advanced/index.html">Advanced</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/robustness.html">Robustness</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/setting-limits.html">Setting 
Limits</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/spooling.html">TikaInputStream and 
Spooling</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/language-detection.html">Language 
Detection</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/language-detection-build.html">Building the Language 
Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charsoup-supported-languages.html">CharSoup Supported 
Languages</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection.html">Text Quality 
Scoring (Junk Detection)</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/junk-detection-build.html">Building 
the Junk Detector</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" 
href="../advanced/charset-detection-design.html">Charset Detection Pipeline</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/zip-detection.html">ZIP Detection 
and Salvaging</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/embedded-documents.html">Embedded 
Document Metadata</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../advanced/local-vlm-server.html">Running a 
Local VLM Server</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <span class="nav-text">Integration Testing</span>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-app.html">Testing with Tika App</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-server.html">Testing with Tika 
Server</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/run-uat-script.html">Tika-Server REST UAT 
Script</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../advanced/integration-testing/tika-eval-regression.html">Regression 
Evaluation with tika-eval</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../security.html">Security</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="index.html">Developers</a>
+<ul class="nav-list">
+  <li class="nav-item is-current-page" data-depth="2">
+    <a class="nav-link" href="serialization.html">Serialization and 
Configuration</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="metadata-keys.html">Adding a Metadata Key</a>
+  </li>
+</ul>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../faq.html">FAQ</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <a class="nav-link" href="../roadmap.html">Roadmap</a>
+  </li>
+  <li class="nav-item" data-depth="1">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" href="../maintainers/index.html">Maintainers</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="2">
+    <a class="nav-link" href="../maintainers/site.html">Publishing the Site</a>
+  </li>
+  <li class="nav-item" data-depth="2">
+    <button class="nav-item-toggle"></button>
+    <a class="nav-link" 
href="../maintainers/release-guides/index.html">Release Guides</a>
+<ul class="nav-list">
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/tika.html">Releasing Apache Tika</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/release-artifacts.html">Release Artifacts: 
What Goes Where</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/docker.html">Releasing Tika Docker 
Images</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/helm.html">Releasing Tika Helm Charts</a>
+  </li>
+  <li class="nav-item" data-depth="3">
+    <a class="nav-link" 
href="../maintainers/release-guides/grpc.html">Releasing Tika gRPC</a>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </li>
+</ul>
+  </nav>
+</div>
+<div class="nav-panel-explore" data-panel="explore">
+  <div class="context">
+    <span class="title">Apache Tika</span>
+    <span class="version">4.0.x</span>
+  </div>
+  <ul class="components">
+    <li class="component is-current">
+      <div class="title"><a href="../index.html">Apache Tika</a></div>
+      <ul class="versions">
+        <li class="version">
+          <a href="../../4.0.1-SNAPSHOT/index.html">4.0.1-SNAPSHOT</a>
+        </li>
+        <li class="version is-current is-latest">
+          <a href="../index.html">4.0.x</a>
+        </li>
+      </ul>
+    </li>
+  </ul>
+</div>
+    </div>
+  </aside>
+</div>
+<main class="article">
+<div class="toolbar" role="navigation" aria-label="Page tools">
+<button class="nav-toggle" aria-label="Toggle navigation"></button>
+</div>
+  <div class="content">
+<aside class="toc sidebar" data-title="Contents" data-levels="2">
+  <div class="toc-menu"></div>
+</aside>
+<article class="doc">
+<h1 class="page">Serialization and Configuration</h1>
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_overview">Overview</a></li>
+<li><a href="#_json_configuration_format">JSON Configuration Format</a></li>
+<li><a href="#_the_tikacomponent_annotation">The @TikaComponent Annotation</a>
+<ul class="sectlevel2">
+<li><a href="#_basic_usage">Basic Usage</a></li>
+<li><a href="#_annotation_attributes">Annotation Attributes</a></li>
+<li><a href="#_example_with_attributes">Example with Attributes</a></li>
+</ul>
+</li>
+<li><a href="#_context_key_detection">Context Key Detection</a>
+<ul class="sectlevel2">
+<li><a href="#_automatic_detection">Automatic Detection</a></li>
+<li><a href="#_explicit_context_key">Explicit Context Key</a></li>
+</ul>
+</li>
+<li><a href="#_service_interface_categories">Service Interface Categories</a>
+<ul class="sectlevel2">
+<li><a href="#_first_class_service_interfaces">First-Class Service 
Interfaces</a></li>
+<li><a href="#_parsecontext_components">ParseContext Components</a></li>
+</ul>
+</li>
+<li><a href="#_self_configuring_components">Self-Configuring 
Components</a></li>
+<li><a href="#_parsecontext_serialization">ParseContext Serialization</a></li>
+<li><a href="#_security_model">Security Model</a>
+<ul class="sectlevel2">
+<li><a href="#_untrusted_wire_input_restricted_mode">Untrusted (Wire) Input: 
Restricted Mode</a></li>
+</ul>
+</li>
+<li><a href="#_framework_directives">Framework Directives</a></li>
+<li><a href="#_creating_a_custom_component">Creating a Custom 
Component</a></li>
+<li><a href="#_troubleshooting">Troubleshooting</a>
+<ul class="sectlevel2">
+<li><a href="#_unknown_component_name_error">"Unknown component name" 
Error</a></li>
+<li><a href="#_component_not_found_in_parsecontext">Component Not Found in 
ParseContext</a></li>
+<li><a href="#_spi_not_loading_component">SPI Not Loading Component</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>Tika 4.x uses JSON-based configuration and serialization throughout the 
system.
+This document explains how the serialization system works and how to create
+components that integrate with it.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_overview"><a class="anchor" href="#_overview"></a>Overview</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Tika&#8217;s serialization system provides:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>JSON Configuration</strong>: Configure Tika components using JSON 
files</p>
+</li>
+<li>
+<p><strong>Friendly Names</strong>: Reference components by name (e.g., 
<code>pdf-parser</code>) instead of class names</p>
+</li>
+<li>
+<p><strong>ParseContext Serialization</strong>: Send per-request configuration 
via <code>FetchEmitTuple</code></p>
+</li>
+<li>
+<p><strong>Security</strong>: Only registered components can be instantiated 
from JSON</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The system is built on Jackson with custom serializers/deserializers in the
+<code>tika-serialization</code> module.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_json_configuration_format"><a class="anchor" 
href="#_json_configuration_format"></a>JSON Configuration Format</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Tika uses a compact format for component configuration:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "auto-detect-parser": {
+    "throwOnZeroBytes": false
+  },
+  "parse-context": {
+    "commons-digester-factory": {
+      "digests": [
+        { "algorithm": "MD5" },
+        { "algorithm": "SHA256" }
+      ]
+    }
+  }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Inside an array-valued section (<code>parsers</code>, 
<code>detectors</code>, <code>encoding-detectors</code>,
+<code>metadata-filters</code>) an element can be specified as:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><strong>String</strong>: <code>"pdf-parser"</code> - creates instance with 
defaults</p>
+</li>
+<li>
+<p><strong>Object</strong>: <code>{"pdf-parser": {"ocr": {"strategy": 
"AUTO"}}}</code> - creates configured instance</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Object-valued sections such as <code>parse-context</code> key each entry by 
name instead, with
+the config object as the value.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_the_tikacomponent_annotation"><a class="anchor" 
href="#_the_tikacomponent_annotation"></a>The @TikaComponent Annotation</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The <code>@TikaComponent</code> annotation is required for any class that 
should be
+configurable via JSON. It serves multiple purposes:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><strong>Registration</strong>: Registers the class with a friendly name</p>
+</li>
+<li>
+<p><strong>Index Generation</strong>: Creates lookup files for name-to-class 
resolution</p>
+</li>
+<li>
+<p><strong>SPI Registration</strong>: Optionally registers for Java 
ServiceLoader</p>
+</li>
+<li>
+<p><strong>Security</strong>: Acts as an allowlist for deserialization</p>
+</li>
+</ol>
+</div>
+<div class="sect2">
+<h3 id="_basic_usage"><a class="anchor" href="#_basic_usage"></a>Basic 
Usage</h3>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">@TikaComponent
+public class MyCustomParser implements Parser {
+    // Parser implementation
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This automatically:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Generates friendly name <code>my-custom-parser</code> from the class 
name</p>
+</li>
+<li>
+<p>Adds to <code>META-INF/tika/parsers.idx</code> for name lookup</p>
+</li>
+<li>
+<p>Adds to <code>META-INF/services/org.apache.tika.parser.Parser</code> for 
SPI</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_annotation_attributes"><a class="anchor" 
href="#_annotation_attributes"></a>Annotation Attributes</h3>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 20%;">
+<col style="width: 20%;">
+<col style="width: 60%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Attribute</th>
+<th class="tableblock halign-left valign-top">Default</th>
+<th class="tableblock halign-left valign-top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>name</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">(auto-generated)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Custom 
friendly name instead of deriving from class name</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>spi</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>true</code></p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Whether to 
register in <code>META-INF/services/</code> for ServiceLoader</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>contextKey</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">(auto-detected)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Class to 
use as ParseContext key (rarely needed)</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>defaultFor</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock">(none)</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Marks as 
default implementation for an interface</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_example_with_attributes"><a class="anchor" 
href="#_example_with_attributes"></a>Example with Attributes</h3>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">@TikaComponent(name = "my-parser", spi = false)
+public class MyInternalParser implements Parser {
+    // Not auto-discovered via SPI, but configurable via JSON
+}</code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_context_key_detection"><a class="anchor" 
href="#_context_key_detection"></a>Context Key Detection</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>When storing components in <code>ParseContext</code>, Tika needs to know 
which class
+to use as the lookup key. For example, <code>CommonsDigesterFactory</code> 
should be
+retrievable via <code>parseContext.get(DigesterFactory.class)</code>.</p>
+</div>
+<div class="sect2">
+<h3 id="_automatic_detection"><a class="anchor" 
href="#_automatic_detection"></a>Automatic Detection</h3>
+<div class="paragraph">
+<p>Tika automatically detects the context key by checking if your class 
implements
+one of these known interfaces:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>Parser</code>, <code>Detector</code>, 
<code>EncodingDetector</code></p>
+</li>
+<li>
+<p><code>MetadataFilter</code>, <code>Translator</code>, 
<code>Renderer</code></p>
+</li>
+<li>
+<p><code>DigesterFactory</code>, <code>ContentHandlerFactory</code>, 
<code>ContentHandlerDecoratorFactory</code></p>
+</li>
+<li>
+<p><code>MetadataWriteLimiterFactory</code>, <code>UnpackSelector</code>, 
<code>EmbeddedDocumentExtractor</code></p>
+</li>
+</ul>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">@TikaComponent
+public class CommonsDigesterFactory implements DigesterFactory {
+    // Context key automatically detected as DigesterFactory.class
+}</code></pre>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_explicit_context_key"><a class="anchor" 
href="#_explicit_context_key"></a>Explicit Context Key</h3>
+<div class="paragraph">
+<p>For interfaces not in the auto-detection list, specify explicitly:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">@TikaComponent(contextKey = DocumentSelector.class)
+public class SkipEmbeddedDocumentSelector implements DocumentSelector { 
}</code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_service_interface_categories"><a class="anchor" 
href="#_service_interface_categories"></a>Service Interface Categories</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_first_class_service_interfaces"><a class="anchor" 
href="#_first_class_service_interfaces"></a>First-Class Service Interfaces</h3>
+<div class="paragraph">
+<p>These are loaded via SPI and have dedicated index files:</p>
+</div>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-left valign-top">Interface</th>
+<th class="tableblock halign-left valign-top">Index File</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>Parser</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>parsers.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>Detector</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>detectors.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>EncodingDetector</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>encoding-detectors.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>LanguageDetector</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>language-detectors.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>Translator</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>translators.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>Renderer</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>renderers.idx</code></p></td>
+</tr>
+<tr>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>MetadataFilter</code></p></td>
+<td class="tableblock halign-left valign-top"><p 
class="tableblock"><code>metadata-filters.idx</code></p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="sect2">
+<h3 id="_parsecontext_components"><a class="anchor" 
href="#_parsecontext_components"></a>ParseContext Components</h3>
+<div class="paragraph">
+<p>Components not implementing first-class interfaces go to 
<code>parse-context.idx</code>:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>DigesterFactory</code> - Digest/checksum calculation</p>
+</li>
+<li>
+<p><code>ContentHandlerFactory</code> - SAX content handler creation</p>
+</li>
+<li>
+<p><code>MetadataWriteLimiterFactory</code> - Metadata write limiting</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_self_configuring_components"><a class="anchor" 
href="#_self_configuring_components"></a>Self-Configuring Components</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p><code>SelfConfiguring</code> is a marker interface with no methods: 
<code>resolveAll</code> skips such
+components, leaving their JSON in <code>ParseContext</code>, and the component 
reads it where
+it needs it. <code>Parser</code> extends <code>SelfConfiguring</code>, so 
every parser is self-configuring.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">@TikaComponent
+public class PDFParser implements Parser {
+
+    private final PDFParserConfig defaultConfig = new PDFParserConfig();
+
+    @Override
+    public void parse(TikaInputStream tis, ContentHandler handler, Metadata 
metadata,
+                      ParseContext parseContext)
+            throws IOException, SAXException, TikaException {
+        PDFParserConfig config = ParseContextConfig.getConfig(
+            parseContext, "pdf-parser", PDFParserConfig.class, defaultConfig);
+        // Use config...
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Benefits:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Per-request configuration via <code>ParseContext</code></p>
+</li>
+<li>
+<p>Lazy loading - config only parsed when needed</p>
+</li>
+<li>
+<p>Merging with defaults handled automatically</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_parsecontext_serialization"><a class="anchor" 
href="#_parsecontext_serialization"></a>ParseContext Serialization</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p><code>ParseContext</code> can be serialized to JSON for transmission (e.g., 
in <code>FetchEmitTuple</code>):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "parse-context": {
+    "pdf-parser": {
+      "ocr": {
+        "strategy": "AUTO"
+      },
+      "extractInlineImages": true
+    },
+    "commons-digester-factory": {
+      "digests": [{"algorithm": "SHA256"}]
+    }
+  }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>All entries use this flat, friendly-named form and are resolved lazily: a 
config
+is parsed into its component only when first needed (see 
<code>resolveAll</code>). There is
+no separate "immediate" or "typed" form.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_security_model"><a class="anchor" 
href="#_security_model"></a>Security Model</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The serialization system implements a security allowlist:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><strong>@TikaComponent Required</strong>: Only annotated classes are 
registered</p>
+</li>
+<li>
+<p><strong>Registry Lookup</strong>: Deserialization only instantiates 
registered classes</p>
+</li>
+<li>
+<p><strong>No Arbitrary Classes</strong>: Unknown class names cause errors, 
not instantiation</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>This prevents attacks where malicious JSON specifies dangerous classes
+for instantiation.</p>
+</div>
+<div class="admonitionblock important">
+<table>
+<tr>
+<td class="icon">
+<i class="fa icon-important" title="Important"></i>
+</td>
+<td class="content">
+<div class="paragraph">
+<p>The allowlist governs <strong>which components may be instantiated</strong> 
from JSON. It does
+not restrict <strong>how an already-loaded component may be 
configured</strong>.</p>
+</div>
+<div class="paragraph">
+<p>Self-configuring components — which includes every <code>Parser</code>, 
since <code>Parser</code>
+extends <code>SelfConfiguring</code> — are skipped by the wire-block scan
+(<code>ParseContextDeserializer.assertNoBlockedComponents</code>): their 
config subtree is
+passed through to the component unexamined. So while a request cannot bind a 
new
+<code>Parser</code> from the wire, a request carrying
+<code>{"parse-context": {"pdf-parser": {"ocr": {"strategy": 
"OCR_AND_TEXT_EXTRACTION"}}}}</code>
+will reach <code>PDFParser</code> and take effect.</p>
+</div>
+<div class="paragraph">
+<p>That is why per-request configuration is gated separately by
+<code>allowPerRequestConfig</code>, which is off by default. Treat "the caller 
may supply
+per-request config" as equivalent to "the caller may set any parser option,
+including options that spawn external processes such as OCR" — not as something
+the allowlist constrains.</p>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "parse-context": {
+    "java.lang.Runtime": {}
+  }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>That fails with "Unrecognized parse-context entry 'java.lang.Runtime'" — 
the class
+is not registered.</p>
+</div>
+<div class="sect2">
+<h3 id="_untrusted_wire_input_restricted_mode"><a class="anchor" 
href="#_untrusted_wire_input_restricted_mode"></a>Untrusted (Wire) Input: 
Restricted Mode</h3>
+<div class="paragraph">
+<p>Configuration files loaded at startup via <code>TikaLoader</code> are 
treated as trusted.
+Per-request configuration arriving over the wire — tika-server request bodies
+and pipes <code>FetchEmitTuple`s — is deserialized in <strong>restricted 
mode</strong>
+(`ParseContextDeserializer.readParseContext(node, true)</code>), which adds a 
second,
+fail-closed gate on top of the registry:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Only context-key types confined to shaping this request&#8217;s metadata or 
output
+may be instantiated from the wire: <code>MetadataFilter</code>, 
<code>ContentHandlerFactory</code>,
+<code>ContentHandlerDecoratorFactory</code>, <code>DigesterFactory</code>,
+<code>MetadataWriteLimiterFactory</code>, <code>UnpackSelector</code></p>
+</li>
+<li>
+<p>Types with exec/IO/network capability or control over which components run
+are blocked: <code>Parser</code>, <code>Detector</code>, 
<code>EncodingDetector</code>, <code>Renderer</code>, <code>Translator</code>,
+<code>EmbeddedDocumentExtractor</code></p>
+</li>
+<li>
+<p>The check is fail-closed: a newly added context-key interface is blocked 
until
+it is consciously allow-listed</p>
+</li>
+<li>
+<p>The whole tree is scanned <strong>before</strong> any component is 
constructed</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>The allowlist/blocklist lives in <code>ComponentNameResolver</code>
+(<code>WIRE_INSTANTIABLE_CONTEXT_KEYS</code> / 
<code>WIRE_BLOCKED_CONTEXT_KEYS</code>); an
+exhaustiveness test asserts every context-key interface is classified as
+exactly one of the two. Plain config DTOs (non-component keys) are never
+blocked.</p>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_framework_directives"><a class="anchor" 
href="#_framework_directives"></a>Framework Directives</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Some JSON keys are consumed by the loading framework itself rather than by 
the
+component whose config object they appear in. When such a directive shares a
+JSON object with a component&#8217;s own properties, it carries a leading 
underscore
+to avoid namespace collisions with legitimate component config keys:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "parsers": [
+    {
+      "pdf-parser": {
+        "_mime-include": ["application/pdf"],
+        "_mime-exclude": ["application/pdf+fdf"],
+        "extractInlineImages": true
+      }
+    }
+  ]
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>_mime-include</code>/<code>_mime-exclude</code> are stripped before 
the component sees its
+config and are applied by the framework as a MIME-filtering decorator around
+the parser. New framework directives must follow the underscore convention.</p>
+</div>
+<div class="paragraph">
+<p>Marker entries that have no component-config namespace of their own are the
+exception: <code>"exclude"</code> on 
<code>default-parser</code>/<code>default-detector</code>/
+<code>default-encoding-detector</code> needs no prefix because those markers 
carry only
+framework keys.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_creating_a_custom_component"><a class="anchor" 
href="#_creating_a_custom_component"></a>Creating a Custom Component</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Complete example of a custom metadata filter. <code>fieldName</code> is 
config-supplied, so it could
+legitimately name a reserved <code>tk:</code> key; use <code>setTrusted</code> 
rather than <code>set</code>&#8201;&#8212;&#8201;filters run
+inside the trusted bracket of <code>MetadataFilter</code>, the sanctioned 
route for a write keyed by
+a name that isn&#8217;t a compile-time constant:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-java hljs" 
data-lang="java">package com.example.tika;
+
+import org.apache.tika.annotation.TikaComponent;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.filter.MetadataFilterBase;
+
+@TikaComponent
+public class UpperCaseFilter extends MetadataFilterBase {
+
+    private String fieldName = "title";
+
+    public void setFieldName(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    @Override
+    protected void filter(Metadata metadata) {
+        String value = metadata.get(fieldName);
+        if (value != null) {
+            metadata.setTrusted(fieldName, value.toUpperCase());
+        }
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Configure in JSON. Metadata filters are loaded via 
<code>parse-context</code> (they
+extend the <code>MetadataFilter</code> abstract class&#8201;&#8212;&#8201;here 
via <code>MetadataFilterBase</code>,
+whose per-<code>Metadata</code> hook suits context-free 
filters&#8201;&#8212;&#8201;which is a
+<code>ParseContext</code>-keyed component):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "parse-context": {
+    "upper-case-filter": {"fieldName": "dc:title"}
+  }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Or with defaults (an empty config object applies no overrides):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlightjs highlight"><code class="language-json hljs" 
data-lang="json">{
+  "parse-context": {
+    "upper-case-filter": {}
+  }
+}</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_troubleshooting"><a class="anchor" 
href="#_troubleshooting"></a>Troubleshooting</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_unknown_component_name_error"><a class="anchor" 
href="#_unknown_component_name_error"></a>"Unknown component name" Error</h3>
+<div class="ulist">
+<ul>
+<li>
+<p>Ensure class has <code>@TikaComponent</code> annotation</p>
+</li>
+<li>
+<p>Verify annotation processing ran during compilation</p>
+</li>
+<li>
+<p>Check that <code>META-INF/tika/*.idx</code> file exists in JAR</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_component_not_found_in_parsecontext"><a class="anchor" 
href="#_component_not_found_in_parsecontext"></a>Component Not Found in 
ParseContext</h3>
+<div class="ulist">
+<ul>
+<li>
+<p>Verify you&#8217;re using the correct interface type for lookup</p>
+</li>
+<li>
+<p>Check if explicit <code>contextKey</code> is needed</p>
+</li>
+<li>
+<p>Self-configuring components are never resolved into the context map; read 
them
+with <code>ParseContextConfig.getConfig(context, "&lt;name&gt;", 
ConfigClass.class, default)</code></p>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_spi_not_loading_component"><a class="anchor" 
href="#_spi_not_loading_component"></a>SPI Not Loading Component</h3>
+<div class="ulist">
+<ul>
+<li>
+<p>Check that <code>spi = true</code> (the default)</p>
+</li>
+<li>
+<p>Verify <code>META-INF/services/</code> file exists</p>
+</li>
+<li>
+<p>Ensure JAR is on classpath</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+</div>
+</article>
+  </div>
+</main>
+</div>
+<footer class="footer">
+  <p>© Apache Software Foundation. All rights reserved.</p>
+</footer>
+<script id="site-script" src="../../../_/js/site.js" 
data-ui-root-path="../../../_"></script>
+<script async src="../../../_/js/vendor/highlight.js"></script>
+<script src="../../../_/js/vendor/lunr.js"></script>
+<script src="../../../_/js/search-ui.js" id="search-ui-script" 
data-site-root-path="../../.." data-snippet-length="150" 
data-stylesheet="../../../_/css/search.css"></script>
+<script async src="../../../search-index.js"></script>
+  </body>
+</html>

Reply via email to