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><meta></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’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 — 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’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’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(…​)</code> for names read out of the document, <code>KeyPrefix.tool(…​)</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’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’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’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’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’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> — filters run +inside the trusted bracket of <code>MetadataFilter</code>, the sanctioned route for a write keyed by +a name that isn’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 — here via <code>MetadataFilterBase</code>, +whose per-<code>Metadata</code> hook suits context-free filters — 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’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, "<name>", 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>
