This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 4b231cf01f TIKA-4808 -- prep CHANGES.txt for release
4b231cf01f is described below
commit 4b231cf01f622b62c4ff272787e993593b23a6aa
Author: tallison <[email protected]>
AuthorDate: Tue Aug 18 11:50:04 2026 -0400
TIKA-4808 -- prep CHANGES.txt for release
---
CHANGES.txt | 783 +++++++++++----------
.../pages/migration-to-4x/migrating-to-4x.adoc | 8 +-
2 files changed, 428 insertions(+), 363 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index c8f38747dc..3b26ecb220 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,100 +1,315 @@
-Release 4.0.0 - ???
+Release 4.0.0 - 8/18/2026
+
+ This section is the complete delta from 3.x. It includes everything first
+ released in 4.0.0-alpha-1 and 4.0.0-beta-1; those sections below are stubs.
+
+ Upgrading from 3.x? Start with the migration guides at
+ https://tika.apache.org/docs -- "Migrating to Tika 4.x", "Migrating Tika
+ Server to 4.x" and "Metadata Changes in Tika 4.x". They carry the detail
+ and the code examples behind the summaries here.
+
+ Important architectural change: parsing now runs in a forked process
+ where possible. tika-server's endpoints, tika-app's -a/--async and -f/--fork,
+ and tika-grpc all parse in forked, crash-isolated tika-pipes workers.
+ Applications embedding Tika should consider getting the same isolation from
+ PipesForkParser (tika-pipes-fork-parser) rather than parsing in-process with
+ AutoDetectParser. Note that the project does not treat denial of service --
+ memory exhaustion, CPU exhaustion, a crashed process -- as a security issue
+ when files are parsed outside these isolated paths; see
+ https://tika.apache.org/security-model.html.
BREAKING CHANGES
- * tika-app: the inline short forms -eX (output encoding) and -pX (document
- password) were removed from standard mode. Use --encoding=X and
- --password=X. These were the only short flags that consumed an inline
- value, and matching them by prefix meant a long name written with one
- dash was silently swallowed: -config=tika.json set the password to
- "onfig=tika.json" and loaded no config file, with no error. Every
- single-dash long name is now rejected with a message naming the
- two-dash form (TIKA-4808).
+ --- Platform, packaging, configuration and output format (everyone) ---
- * tika-core/tika-app: NetworkParser and tika-app's -c/--client=<uri>
- network-client mode were removed. It dispatched raw sockets
- (including a bare telnet:// scheme) to an arbitrary user-supplied
- host with no auth or TLS enforcement; use tika-server instead
- (TIKA-4808).
+ * Tika 4.x requires Java 17 or later; 3.x built and ran on Java 11. All
+ published artifacts are compiled with --release 17 (TIKA-4685).
+
+ * tika-app and tika-server-standard now ship as zip distributions with an
+ adjacent lib/ directory; the published jars are thin launchers and fail
+ with NoClassDefFoundError if run on their own. This catches
+ tika-server-standard hardest, because its jar is still on Maven Central:
+ unzip the distribution and run from inside it (TIKA-4733).
+
+ * tika-parsers-standard-package is now a pom, not a jar. Users must add
+ <type>pom</type> in Maven or @pom in Gradle (TIKA-4712).
+
+ * The default content handler is now Markdown. tika-app, tika-server (the
+ /tika and /rmeta endpoints) and the async/pipes CLI emit Markdown content
+ by default instead of XHTML/XML (plain text for the async CLI). Request
+ the previous format explicitly: tika-app -x/--xml, the server's /tika/xml
+ and /rmeta/xml paths, the async CLI --handler x (TIKA-4663).
+
+ * Configuration moved from XML to JSON. TikaConfig and the
+ org.apache.tika.config XML-configuration API are removed: TikaConfig,
+ ConfigBase, Field, Param, ParamField, LoadErrorHandler,
+ InitializableProblemHandler, TikaConfigSerializer and TikaTaskTimeout are
+ gone. Use TikaLoader from tika-serialization. tika-app
+ --convert-config-xml-to-json converts a 3.x parsers section as a starting
+ point; every other section needs manual migration
+ (TIKA-4544, TIKA-4545, TIKA-4553, TIKA-4565).
- * Metadata's reserved tk: (and legacy X-TIKA:) namespace is now a trust
- boundary for String-keyed writes. A String write to a reserved key throws
- IllegalArgumentException instead of 3.x's silent success or silent drop,
- and the public Property factories reject reserved names outright -- a
- curated tk: constant can only be built from Tika's own package-private
- factories.
- Metadata#setAll(Properties) is removed with no replacement; use
- putAll(Metadata) or individual set/add calls. PassthroughPrefix is
- renamed to KeyPrefix, and document/tool-derived names are written via the
- new Metadata#add(KeyPrefix, String, String) route (append-only, with
- built-in skip-and-WARN bounds on hostile names) or its Instant overload
- for source-typed dates. A batch of key families was also renamed into
- namespaced spellings (audio:, ner:, envi:, ogg:streams-, grobid:,
- iso19115:, gdal:, geotopic:, mif:, idml:, and GeoParser's Optional_NAME<n>
- fields); see the metadata key migration guide (metadata-changes-4x.adoc)
- for the full renamed-key table.
- Metadata no longer implements CreativeCommons, Geographic, HttpHeaders,
- Message, ClimateForcast, TIFF, or TikaMimeKeys: inherited constants like
- Metadata.CONTENT_TYPE move to their home interface
(HttpHeaders.CONTENT_TYPE,
- etc.). The TikaMimeKeys and ClimateForcast interfaces are deleted
outright;
- ClimateForecast (corrected spelling) replaces the latter. The Property
- factories internalClosedChoise/internalOpenChoise/externalClosedChoise/
- externalOpenChoise are renamed to ...Choice (typo fix, no forwarders), and
- the dead enum constants PropertyType.STRUCTURE and ValueType.{LOCALE,
- MIME_TYPE, PROPER_NAME, URL, XPATH} are removed. The remaining metadata
- API cleanups (cf: prefix, writelimiter package, smaller removals) are
- enumerated in the migration guide, migrating-to-4x.adoc (TIKA-4816).
+ * An unregistered component name in a default-parser, default-detector or
+ default-encoding-detector "exclude" list now throws a TikaConfigException
+ at config load instead of logging a WARN, so a 3.x config that named the
+ component by class name or misspelled it now refuses to start. Use the
+ registered name (e.g. "pdf-parser"); tika-app --list-parser-names prints
+ them (TIKA-3268, TIKA-4808).
+
+ * Metadata keys were renamed for consistency and provenance. Every
+ Tika-asserted key now lives under a single tk: prefix, replacing 3.x's
+ scattered X-TIKA:, tika:, tika_pg:, rendering:, signature: and
+ imagereader: prefixes and bare names such as resourceName; names Tika
+ coined inside format namespaces are kebab-cased (pdf:hasMarkedContent ->
+ pdf:has-marked-content) while names from a file or an external standard
+ keep their spelling; and open key families gained prefixes (audio:, ner:,
+ envi:, ogg:streams-, grobid:, iso19115:, gdal:, geotopic:, mif:, idml:).
+ Code using the TikaCoreProperties / TikaPagedText / Rendering constants is
+ unaffected. Code that references keys by String has two paths: update the
+ strings with the key-for-key tables in metadata-changes-4x.adoc, or turn
+ on the compatibility filter below and migrate on your own schedule
+ (TIKA-4816).
+
+ * The opt-in legacy-key-migration-filter restores 3.x key spellings at the
+ emit edge (default direction V4_TO_V3), so an unmigrated consumer keeps
+ working against 4.x output; V3_TO_V4 maps 3.x names forward instead.
+ tika-core bundles metadata-migration-3x-4x.json, the machine-readable
+ rename/drop table (TIKA-4797).
+
+ * The reserved tk: (and legacy X-TIKA:) namespace is now a trust boundary
+ for String-keyed writes. Metadata#set/add(String, String) throw
+ IllegalArgumentException on a reserved key instead of 3.x's silent
+ success, where a document-controlled property named X-TIKA:Parsed-By could
+ overwrite Tika's own value, and Property's public factories reject
reserved
+ names outright. Document- and tool-derived names now go through
+ Metadata#add(KeyPrefix, String, String) -- append-only, skip-and-WARN on
+ hostile names -- or its Instant overload for source-typed dates
+ (TIKA-4816).
+
+ * Metadata no longer implements CreativeCommons, Geographic, HttpHeaders,
+ Message, ClimateForcast, TIFF or TikaMimeKeys: inherited constants move to
+ their home interface, e.g. Metadata.CONTENT_TYPE becomes
+ HttpHeaders.CONTENT_TYPE (now a Property, though the key string is
+ unchanged). TikaMimeKeys and
+ ClimateForcast are deleted outright; ClimateForecast (corrected spelling)
+ replaces the latter, with its keys under cf: (TIKA-4816).
+
+ * Other Metadata API changes: setAll(Properties) removed with no replacement
+ -- it bypassed both the limiter and the reserved-key guard, so use
+ putAll(Metadata) or individual set/add calls; PassthroughPrefix renamed
+ KeyPrefix; the Property factories internalClosedChoise /
internalOpenChoise
+ / externalClosedChoise / externalOpenChoise renamed to ...Choice with no
+ forwarders; the dead enum constants PropertyType.STRUCTURE and
+ ValueType.{LOCALE, MIME_TYPE, PROPER_NAME, URL, XPATH} removed; package
+ org.apache.tika.metadata.writefilter renamed to ...metadata.writelimiter.
+ Metadata's serialVersionUID also changed, so a 3.x-serialized instance now
+ fails with InvalidClassException instead of deserializing into an object
+ that throws on first write (TIKA-4816).
+
+ --- Java API (library integrators) ---
+
+ * The core SPI signatures changed. Parser.parse takes a TikaInputStream
+ instead of an InputStream (there is no InputStream overload),
+ Detector.detect takes (TikaInputStream, Metadata, ParseContext), and
+ EmbeddedDocumentExtractor's shouldParseEmbedded/parseEmbedded gained a
+ ParseContext and take a TikaInputStream. Every third-party implementation
+ must be updated; callers can wrap with TikaInputStream.get(...). The Tika
+ facade still accepts an InputStream, but Tika.detect(InputStream, ...) no
+ longer returns the caller's stream at its original position. The detector
+ still resets the TikaInputStream it reads -- but that read-ahead is
+ buffered inside an internal wrapper that detect() discards, so the
+ caller's own stream comes back advanced. Pass a TikaInputStream you own
+ (and rewind it), or re-open the source
+ (TIKA-4399, TIKA-4541, TIKA-4569).
+
+ * TikaInputStream no longer caches by default. A stream is consumed in
+ passthrough mode unless enableRewind() is called at position 0;
+ rewind()/getFile()/getPath() after reading without enableRewind() throw
+ instead of silently spooling. A parser that read part of a stream and then
+ asked for a file worked in 3.x and now fails. Digesters call
+ enableRewind() themselves (TIKA-4618, TIKA-4623).
* Parsing with a concrete parser (not AutoDetectParser) and an empty
ParseContext no longer auto-generates an AutoDetectParser to handle
- embedded files. Users must set the Parser of their choice for embedded
- files. EmbeddedDocumentExtractorFactory and friends are removed;
- ParsingEmbeddedDocumentExtractor/UnpackExtractor are now stateless
- singletons (TIKA-4819).
+ embedded files: they are silently skipped, with no content and no
+ exception. Nor does it auto-generate a Detector to identify them; they are
+ reported as application/octet-stream instead. Set Parser.class and
+ Detector.class in the ParseContext, or go through AutoDetectParser, which
+ does this for you (TIKA-4819).
+
+ * EmbeddedDocumentExtractorFactory and friends are removed;
+ ParsingEmbeddedDocumentExtractor and UnpackExtractor are now stateless
+ singletons (use INSTANCE) that take the enclosing ParseContext as a method
+ parameter rather than capturing one at construction. Code that supplied a
+ custom factory should bind an EmbeddedDocumentExtractor instance directly.
+ EmbeddedDocumentUtil's instance API is likewise removed in favor of
statics
+ that take a ParseContext explicitly (TIKA-4819).
- * Parsing with a concrete parser (not AutoDetectParser) and an empty
- ParseContext no longer auto-generates a Detector to identify embedded
- files; they are reported as application/octet-stream instead. Users
- must set the Detector of their choice for embedded files (TIKA-4819).
+ * ParseContext configuration is now resolved per component instance rather
+ than per config class, because a class-keyed write leaked one component's
+ config to every other component binding the same config class. Two
+ consequences: parseContext.get(SomeConfig.class) no longer returns a
+ JSON-resolved config, so a third-party component following the
+ PDFBoxRenderer pattern must be handed its config explicitly; and
precedence
+ is inverted -- a JSON config now beats a programmatic
+ context.set(XConfig.class, ...), which used to win (TIKA-4808).
+
+ * ForkParser and the entire org.apache.tika.fork package are removed from
+ tika-core. Out-of-process parsing is now provided by PipesForkParser in
+ the new tika-pipes-fork-parser module -- the recommended parser for
+ untrusted documents. tika-app's -f/--fork routes through it, and
+ --fork-timeout is rejected rather than silently ignored
+ (TIKA-4554, TIKA-4571, TIKA-4651).
- * tika-server: the /translate endpoints have been removed (TIKA-4809).
+ * Unified timeout model across the library, pipes and server: a total-task
+ budget plus a progress/stall timeout, composed recursively over embedded
+ documents. TikaTimeoutException is now a checked exception, and several
+ parser/pipes config fields were renamed (*TimeoutSeconds / *TimeoutMs ->
+ *TimeoutMillis, including a unit change for Tess4J) (TIKA-4813).
- * tika-server: /detect/stream and /language/stream and /language/string have
- been collapsed into /detect and /language (TIKA-4809).
+ * Parsers and detectors no longer expose bean setters/getters for their
+ settings. Configuration moves to per-component *Config objects supplied
+ through the ParseContext (e.g. GeoParserConfig, DWGParserConfig,
+ AmazonTranscribeConfig, MagikaDetector/SiegfriedDetector configs)
+ (TIKA-4758).
- * tika-server: caller errors now map to accurate HTTP status codes instead
of
- always returning 200 or 500. A saturated worker pool returns 429, a
- crashed/timed-out/OOM worker returns 503, an unknown or reserved
- fetcher/emitter or bad handler returns 400, and an over-limit body returns
- 413; the 429 and 503 responses carry a Retry-After header (TIKA-4809).
+ * The encoding detectors moved out of parser packages into
+ org.apache.tika.detect.* and into new tika-encoding-detector-* modules:
+ org.apache.tika.parser.txt.{CharsetDetector,CharsetMatch,
+ Icu4jEncodingDetector,UniversalEncodingDetector,BOMDetector,...} are now
+ org.apache.tika.detect.icu4j.*, org.apache.tika.detect.universal.* and
+ org.apache.tika.detect.BOMDetector, and
+ org.apache.tika.parser.html.HtmlEncodingDetector is now
+ org.apache.tika.detect.html.HtmlEncodingDetector.
+ NonDetectingEncodingDetector is removed (TIKA-4685, TIKA-4720).
- * tika-server: the bare /tika endpoint now returns Markdown too (was XHTML),
- completing the Markdown default (TIKA-4663); use /tika/xml for XHTML
(TIKA-4809).
+ * MetadataListFilter has been renamed MetadataFilter, and the 3.x
+ MetadataFilter has been removed (TIKA-4546).
+
+ * API changes in the EmbeddedStreamTranslator (TIKA-4518), and
+ DigestingParser is removed (TIKA-4607).
- * tika-server: request bodies are now capped by maxRequestSizeBytes,
- defaulting to 1 GiB; larger requests are rejected with 413, including
- over-limit chunked uploads, which previously surfaced as an empty 500
+ * BasicContentHandlerFactory.parseHandlerType now throws
+ IllegalArgumentException for an unrecognized handler name instead of
+ silently returning the supplied default (TIKA-4809).
+
+ --- tika-server ---
+
+ * All parsing now runs out-of-process through tika-pipes. /tika, /rmeta,
+ /meta, /unpack, /detect, /pipes and /async share a fixed pool of
+ numClients forked worker JVMs (default derived from host cores), so a
+ parser crash, OOM or timeout no longer takes down the server. The cost is
+ a sizing decision 3.x never asked of you: numClients is both the server's
+ concurrency ceiling and its CPU/memory footprint, and each fork's heap is
+ set with pipes.forkedJvmArgs (e.g. -Xmx1g), not the server JVM's. Size
+ both deliberately; see the cpu-sizing docs (TIKA-4809).
+
+ * Capability flags are default-deny and split in two. enableUnsecureFeatures
+ no longer exists -- a config still carrying it fails to start with an
+ "Unrecognized field" error -- and is replaced by allowPipes (gates /pipes
+ and /async) and allowPerRequestConfig (gates the /config endpoints and the
+ multipart config part). /status is no longer gated and is enabled simply
+ by listing it under endpoints. tika-grpc gains
+ the same allowPerRequestConfig flag plus allowComponentModifications,
which
+ gates runtime Save/Delete of fetchers and pipes iterators (TIKA-4764).
+
+ * Endpoints removed: /translate/* (unusable as shipped), /tika/main and
+ /tika/form/main (Boilerpipe; use /tika/text), and the /tika/form family.
+ The 3.x /tika/config and /tika/form/config forms are replaced by the
+ /tika/config* multipart POSTs, which require allowPerRequestConfig
(TIKA-4809).
- * tika-server: a /meta request with no Accept header now returns JSON;
- 3.x returned CSV. CSV is still available via Accept: text/csv (TIKA-4809).
+ * Endpoints collapsed: /detect/stream is now /detect, and /language/stream
+ and /language/string are both /language. Behavior changed with the rename:
+ /detect now runs in the fork pool, so it can return 429, 503 or 413, and a
+ failure reading the body is a 500 where 3.x returned 200 with
+ application/octet-stream as if detection had succeeded; /language caps
+ input at the first 100,000 characters and uses the default
LanguageDetector
+ on the classpath, where 3.x pinned Optimaize (TIKA-4809).
+
+ * Output-format routing on /tika changed. The bare /tika endpoint returns
+ Markdown (was XHTML); use /tika/xml for XHTML. /tika/text is body-only
+ again, as in 3.x. /tika/json and /tika/config/json default to the server
+ default (markdown) rather than hardcoded plain text. The Accept header no
+ longer selects the output format -- 3.x routed bare /tika among plain
+ text, HTML and XHTML by Accept (nondeterministically for */*); now the
+ path names the format. An unrecognized handler name in the path is a 400
+ listing the valid types, instead of silently falling back to the default
+ (TIKA-4663, TIKA-4809).
+
+ * Per-request configuration headers are removed, and are now silently
+ ignored if sent: writeLimit, throwOnWriteLimitReached,
+ maxEmbeddedResources/maxEmbeddedCount, X-Tika-Handler and the meta_*
+ metadata-injection family. The limits move to parse-context
+ (output-limits.writeLimit, output-limits.throwOnWriteLimit,
+ embedded-limits.maxCount); X-Tika-Handler becomes an explicit handler
path;
+ meta_* has no replacement, and with per-request config off by default a
+ caller can no longer bound the output of a single request. The
+ X-Tika-OCR* and X-Tika-PDF* families were removed earlier in the 4.x line
+ (TIKA-4809).
- * tika-server: the raw /tika family's 422 responses carry the extracted
- content only; the exception is no longer appended to the body -- use
- /rmeta for the structured exception (TIKA-4809).
+ * Caller errors now map to accurate HTTP status codes instead of always
+ returning 200 or 500. A saturated worker pool returns 429, a
+ crashed/timed-out/OOM worker returns 503, an unknown or reserved
+ fetcher/emitter or bad handler returns 400, and an over-limit body returns
+ 413; the 429 and 503 responses carry a Retry-After header. Error bodies
are
+ now JSON ({"status":"TIMEOUT"}, with a message field when one is
+ available) where 3.x returned plain text such as "Parse failed: TIMEOUT"
+ (TIKA-4809).
- * tika-server: /async validates fetcher/emitter ids at POST time (400),
- rejects a batch larger than the queue's total capacity with 400 instead
- of throttling it, and one bad tuple no longer stops the async workers
+ * The raw /tika family's 422 responses carry the extracted content only; the
+ exception is no longer appended to the body -- use /rmeta for the
+ structured exception (TIKA-4809).
+
+ * /meta now runs through the same pipes-backed parser as the other
+ extraction endpoints, so it gains their crash isolation and their error
+ handling: a container exception comes back as 200 with
+ tk:exception:container-exception instead of 500, and /meta/{field} returns
+ 422 instead of 500 or 400. A request with no Accept header now returns
+ JSON; 3.x returned CSV, still available via Accept: text/csv. /meta also
no
+ longer returns a language field -- it parses with the ignore handler, so
+ there is no text to detect from; configure a language-detection metadata
+ filter and use /rmeta or /tika/json instead (TIKA-4809).
+
+ * /async requires an object body {"tuples":[...]} instead of a bare JSON
+ array, validates fetcher/emitter ids at POST time (400), rejects a batch
+ larger than the queue's total capacity with 400 instead of throttling it,
+ and one bad tuple no longer stops the async workers. /pipes returns the
+ same JSON body as /tika/rmeta/unpack -- {"status":<RESULT_STATUS>,
+ "message":...} -- instead of a /pipes-only {"status":"ok"|"process_crash"}
+ shape, returns 400 with the reason for a malformed request body, and
+ rejects emit strategies other than EMIT_ALL, whose passed-back data the
+ /pipes response cannot carry (TIKA-4809).
+
+ * Many server config keys were removed or renamed (logLevel, idBase,
+ digest, returnStackTrace, port ranges, the spawn-child options, ...), and
+ an unrecognized key now fails startup with an error naming it; see
+ migrating-tika-server-4x.adoc for the key-by-key migration. One change no
+ startup error will flag: taskTimeoutMillis is now
+ parse-context.timeout-limits.totalTaskTimeoutMillis, and its default grew
+ from 5 minutes to 1 hour (TIKA-4809, TIKA-4813).
+
+ * Request bodies are now capped by maxRequestSizeBytes, defaulting to 1 GiB;
+ larger requests are rejected with 413, including over-limit chunked
+ uploads, which previously surfaced as an empty 500 (TIKA-4809).
+
+ * The 'endpoints' allowlist now also gates SPI-provided resources; a
+ discovered resource binds only when its root endpoint is enabled
(TIKA-4809).
- * tika-server: /pipes returns 400 with the reason for a malformed request
- body and rejects emit strategies other than EMIT_ALL, whose passed-back
- data the /pipes response cannot carry (TIKA-4809).
+ * Fetcher-based streaming is removed: the InputStreamFactory pattern for
+ fetching documents via the fetcherName/fetchKey headers is gone, and all
+ documents now go through the pipes infrastructure. The no-op
+ -a/--pluginsConfig flag is removed and now fails option parsing, --help
+ exits 0, and the tika-server-client module is removed (TIKA-4809).
+
+ --- tika-pipes and tika-grpc ---
- * tika-server: the 'endpoints' allowlist now also gates SPI-provided
- resources; a discovered resource binds only when its root endpoint is
- enabled (TIKA-4809).
+ * tika-pipes implementation modules are now pf4j plugins, reorganized by
+ resource (tika-pipes-solr) vs task (tika-pipes-fetcher-solr). Core classes
+ moved to tika-pipes-core, and the file-system components moved out of it
+ into their own tika-pipes-file-system plugin
+ (TIKA-4334, TIKA-4519, TIKA-4543).
* FetchEmitTuple JSON now names the per-tuple parse context "parse-context"
(was "parseContext") and rejects unknown tuple fields with an error naming
@@ -104,51 +319,6 @@ Release 4.0.0 - ???
staleFetcherDelaySeconds have been removed; a config still carrying them
fails startup (TIKA-4809).
- * An unregistered component name in a default-parser, default-detector or
- default-encoding-detector "exclude" list now throws a TikaConfigException
- at config load instead of logging a WARN. Silently ignoring an exclusion
- left a deliberately disabled component enabled. A config that loaded with
- a warning on 3.x -- typically one that names the excluded component by
- class name, or misspells it -- now refuses to start. Use the registered
- component name (e.g. "pdf-parser"); tika-app --list-parser-names prints
- them (TIKA-3268, TIKA-4808).
-
- * ParseContext configuration is now resolved per component instance rather
- than per config class. ConfigDeserializer no longer publishes a resolved
- config under its class, because a class-keyed write leaked one component's
- config to every other component sharing that config class -- the three VLM
- parsers all bind VLMOCRConfig, so one provider's base URL and API key
- reached the other two. Two user-visible consequences:
- parseContext.get(SomeConfig.class) no longer returns a JSON-resolved
- config, so a third-party component following the PDFBoxRenderer pattern
- must now be handed its config explicitly; and precedence is inverted --
- a JSON config for a key now beats a programmatic
- context.set(XConfig.class, ...), where the programmatic value used to win.
- The programmatic value is still honored for a key with no JSON config.
- Resolved configs are cached by (component name, config class), so a
- component that resolves a validation-only RuntimeConfig and then
- re-resolves its real config class gets each as its own instance and still
- merges the operator's defaults (TIKA-4808).
-
- * tika-grpc: the generated Java classes moved from package org.apache.tika
- to org.apache.tika.pipes.grpc.proto (java_package in tika.proto;
- java_multiple_files stays true), so every generated type moves --
- TikaGrpc, FetchAndParseRequest, FetchAndParseReply and the rest. Java gRPC
- clients must update their imports. This is a source break only: the proto
- package ("tika") and the service name ("Tika") are unchanged, so the wire
- protocol is identical and clients in other languages, or Java clients that
- are not recompiled, are unaffected (TIKA-4808).
-
- * ExceptionUtils.trimMessage has been removed from tika-core; it moved into
- tika-eval-core (TIKA-4809).
-
- * BasicContentHandlerFactory.parseHandlerType now throws
- IllegalArgumentException for an unrecognized handler name instead of
- silently returning the supplied default (TIKA-4809).
-
- * HttpClientFactory's inert redirect-host allowlist accessors
- (get/setAllowedHostsForRedirect) have been removed (TIKA-4809).
-
* TimeoutLimits: progressTimeoutMillis of 0 combined with a positive
totalTaskTimeoutMillis is now rejected at config load; it would kill
every task immediately (TIKA-4809).
@@ -156,58 +326,42 @@ Release 4.0.0 - ???
* The http-fetcher now verifies TLS certificates and hostnames by default;
set verifySsl:false to opt out (TIKA-4809).
- * tika-server: /pipes returns the same JSON body as /tika/rmeta/unpack --
- {"status":<RESULT_STATUS>,"message":...} -- instead of a /pipes-only
- {"status":"ok"|"process_crash",...} shape (TIKA-4809).
+ * SolrJ moves from 8.11.4 to 10.0.0; the Solr fetcher, emitter and pipes
+ iterator no longer support Solr 8 (TIKA-4789).
- * tika-server: POST /async requires an object body {"tuples":[...]} instead
of
- a bare JSON array (TIKA-4809).
+ * tika-grpc: the generated Java classes moved from package org.apache.tika
+ to org.apache.tika.pipes.grpc.proto, so every generated type moves and
Java
+ gRPC clients must update their imports. This is a source break only: the
+ proto package ("tika") and the service name ("Tika") are unchanged, so the
+ wire protocol is identical and clients in other languages are unaffected
+ (TIKA-4808).
- * tika-server: the tika-server-client module has been removed (TIKA-4809).
+ --- tika-app and tika-eval-app ---
- * Tika 4.x requires Java 17 or later; 3.x built and ran on Java 11. All
- published artifacts are compiled with --release 17 (TIKA-4685).
-
- * The core SPI signatures changed. Parser.parse now takes a TikaInputStream
- instead of an InputStream (there is no InputStream overload),
- Detector.detect takes (TikaInputStream, Metadata, ParseContext) instead of
- (InputStream, Metadata), and EmbeddedDocumentExtractor's
- shouldParseEmbedded/parseEmbedded gained a ParseContext and take a
- TikaInputStream. Every third-party Parser, Detector or
- EmbeddedDocumentExtractor implementation must be updated; callers can wrap
- with TikaInputStream.get(...). The Tika facade (Tika.parse/parseToString)
- still accepts an InputStream and is unaffected. Tika.detect(InputStream,
...)
- no longer resets the stream to its original position: detection now reads
- ahead through a TikaInputStream, so on return the caller's stream must be
- treated as consumed. It still does not close the caller's stream, and any
- temporary file spooled during detection is deleted before it returns
- (TIKA-4399, TIKA-4541, TIKA-4569).
+ * tika-app's batch mode is gone. The -bc/batch directory-to-directory
command
+ line (backed by the removed tika-batch module) has no successor flag; use
+ -a/--async, which runs the same work through tika-pipes
+ (TIKA-4333, TIKA-4340).
- * TikaConfig and the org.apache.tika.config XML-configuration API are
- removed: TikaConfig, ConfigBase, Field, Param, ParamField,
- LoadErrorHandler, InitializableProblemHandler, TikaConfigSerializer and
- TikaTaskTimeout are gone. Use TikaLoader from tika-serialization; see
- migrating-to-4x.adoc (TIKA-4545, TIKA-4553, TIKA-4565).
+ * tika-core/tika-app: NetworkParser and tika-app's -c/--client=<uri>
+ network-client mode were removed -- they dispatched raw sockets to an
+ arbitrary user-supplied host with no auth or TLS. Use tika-server
+ instead (TIKA-4808).
- * ForkParser and the entire org.apache.tika.fork package are removed from
- tika-core. Out-of-process parsing is now provided by PipesForkParser in
- the new tika-pipes-fork-parser module. tika-app's -f/--fork routes through
- it, and --fork-timeout is rejected rather than silently ignored
- (TIKA-4554, TIKA-4571, TIKA-4651).
+ * tika-eval-app's command line changed: the FileProfile sub-command is
+ removed, the -bc batch-config option is gone, and extract directories are
+ now named with -e/--extracts (Profile) and -a/--extractsA + -b/--extractsB
+ (Compare); -i/--inputDir, -d/--db, -c/--config, -n/--numWorkers and
+ -m/--maxExtractLength replace the 3.x spellings
+ (TIKA-4342, TIKA-4450, TIKA-4452, TIKA-4507).
- * tika-app and tika-server-standard now ship as zip distributions with an
- adjacent lib/ directory; the published jars are thin launchers and fail
- with NoClassDefFoundError if run on their own (TIKA-4733).
+ * tika-app: the inline short forms -eX (output encoding) and -pX (document
+ password) were removed from standard mode; use --encoding=X and
+ --password=X. Prefix-matching them silently swallowed single-dash long
+ names, so every single-dash long name is now rejected with a message
+ naming the two-dash form (TIKA-4808).
- * The encoding detectors moved out of parser packages into
- org.apache.tika.detect.* and into new tika-encoding-detector-* modules:
- org.apache.tika.parser.txt.{CharsetDetector,CharsetMatch,
- Icu4jEncodingDetector,UniversalEncodingDetector,BOMDetector,...} are now
- org.apache.tika.detect.icu4j.*, org.apache.tika.detect.universal.* and
- org.apache.tika.detect.BOMDetector, and
- org.apache.tika.parser.html.HtmlEncodingDetector is now
- org.apache.tika.detect.html.HtmlEncodingDetector.
- NonDetectingEncodingDetector is removed (TIKA-4685, TIKA-4720).
+ --- Parser, detector and output behavior ---
* The tika-langdetect-tika module is removed (TikaLanguageDetector,
LanguageIdentifier, LanguageProfile, LanguageProfilerBuilder,
@@ -216,23 +370,15 @@ Release 4.0.0 - ???
tika-langdetect-optimaize, so the language reported by default changes
(TIKA-4662).
- * SolrJ moves from 8.11.4 to 10.0.0; the Solr fetcher, emitter and pipes
- iterator no longer support Solr 8 (TIKA-4789).
-
- * tika-app's batch mode is gone. The -bc/batch directory-to-directory
command
- line (backed by the removed tika-batch module) has no successor flag; use
- -a/--async, which runs the same work through tika-pipes (TIKA-4340).
-
- * Metadata's serialVersionUID changed. A Metadata instance serialized by 3.x
- now fails deserialization with InvalidClassException instead of silently
- producing an object with a null write limiter that throws on first write
- (TIKA-4816).
-
* PDF: extractIncrementalUpdateInfo now defaults to true (was false), so
every PDF parse emits pdf:incremental-update-count and related keys
without configuration. parseIncrementalUpdates remains false
(TIKA-4354, TIKA-4358).
+ * Audio cover art is now extracted as embedded documents from MP3 (ID3v2
+ APIC/PIC), MP4 (covr), Vorbis and FLAC. Embedded-document counts and
+ /rmeta list lengths for audio files change (TIKA-4801).
+
* The DOM-based OOXML extractors are removed (XWPFWordExtractorDecorator,
XSLFPowerPointExtractorDecorator, POIXMLTextExtractorDecorator,
XPSTextExtractor) and with them the OfficeParserConfig keys
@@ -243,55 +389,42 @@ Release 4.0.0 - ???
page rendering for OCR now uses the PDFBox renderer or the new
PopplerRenderer (TIKA-4664).
- * Parsers and detectors no longer expose bean setters/getters for their
- settings. Configuration moves to per-component *Config objects supplied
- through the ParseContext (e.g. GeoParserConfig, DWGParserConfig,
- AmazonTranscribeConfig, MagikaDetector/SiegfriedDetector configs)
- (TIKA-4758).
-
- * TikaInputStream no longer caches by default. A stream is consumed in
- passthrough mode unless enableRewind() is called at position 0;
- rewind()/getFile()/getPath() after reading without enableRewind() throw
- instead of silently spooling. Digesters call enableRewind() themselves
- (TIKA-4618, TIKA-4623).
-
- * tika-eval-app's command line changed: the FileProfile sub-command is
- removed, the -bc batch-config option is gone, and extract directories are
- now named with -e/--extracts (Profile) and -a/--extractsA + -b/--extractsB
- (Compare); -i/--inputDir, -d/--db, -c/--config, -n/--numWorkers and
- -m/--maxExtractLength replace the 3.x spellings
- (TIKA-4342, TIKA-4450, TIKA-4452, TIKA-4507).
-
- * Audio cover art is now extracted as embedded documents from MP3 (ID3v2
- APIC/PIC), MP4 (covr), Vorbis and FLAC. Embedded-document counts and
- /rmeta list lengths for audio files change (TIKA-4801).
-
- * Additional removals with no direct replacement: the tika-server-eval
- module (TIKA-4555); SentimentAnalysisParser (TIKA-4574); the
- tika-age-recogniser module / AgeRecogniser (TIKA-4343);
- ObjectRecognitionParser and the Tensorflow recognisers/captioners;
- PooledTimeSeriesParser; org.apache.tika.parser.pdf.AccessChecker
- (replaced by PDFParserConfig.AccessCheckMode);
- org.apache.tika.utils.{RereadableInputStream,AnnotationUtils};
- org.apache.tika.io.{IOUtils,InputStreamFactory};
- org.apache.tika.sax.DIFContentHandler;
- org.apache.tika.parser.{AutoDetectParserFactory,ParserFactory};
- org.apache.tika.parser.internal.Activator; and the jempbox-based
- JempboxExtractor / XMPMetadataExtractor / pdf.xmpschemas.* classes
- superseded by the unified XMP extractor (TIKA-4775).
+ * The legacy ExternalParser is removed; external parsers now require
explicit
+ JSON configuration. CompositeExternalParser and ExternalParsersFactory,
+ which loaded tika-external-parsers.xml definitions from the classpath
+ automatically, are gone (TIKA-4707).
+
+ * Headers are no longer injected into the body/content of MSG files
+ (TIKA-4345). Please open a ticket if you need this behavior across email
+ formats.
+
+ --- Removed modules and classes ---
+
+ * Removed modules with no direct replacement: tika-batch (TIKA-4333),
+ tika-dl (TIKA-4499), the advanced media module (TIKA-4500), tika-fuzzing
+ (TIKA-4506), tika-age-recogniser (TIKA-4343), tika-server-eval
+ (TIKA-4555), the dotnet bindings (TIKA-4332) and snaps deployment
+ (TIKA-4502).
+
+ * Removed parsers and classes with no direct replacement:
+ SentimentAnalysisParser (TIKA-4574); ObjectRecognitionParser and the
+ Tensorflow recognisers/captioners; PooledTimeSeriesParser;
+ org.apache.tika.parser.pdf.AccessChecker (replaced by
+ PDFParserConfig.AccessCheckMode); and the jempbox-based JempboxExtractor /
+ XMPMetadataExtractor / pdf.xmpschemas.* classes superseded by the unified
+ XMP extractor (TIKA-4775).
+
+ * Smaller removals: ExceptionUtils.trimMessage moved from tika-core to
+ tika-eval-core; HttpClientFactory's inert redirect-host allowlist
+ accessors (get/setAllowedHostsForRedirect) are gone (TIKA-4809); and
+ org.apache.tika.utils.{RereadableInputStream,AnnotationUtils},
+ org.apache.tika.io.{IOUtils,InputStreamFactory},
+ org.apache.tika.sax.DIFContentHandler,
+ org.apache.tika.parser.{AutoDetectParserFactory,ParserFactory} and
+ org.apache.tika.parser.internal.Activator are removed.
NEW FEATURES
- * Content-based detection of ASN.1/DER crypto containers. Magic for the
- PKCS#7/CMS arc ships enabled by default: application/pkcs7-mime gained
- magic (3.x had globs only), application/pkcs7-signature's magic was
- broadened across the DER length forms, and application/timestamped-data,
- application/x-pkcs12, application/x-pkcs7-certificates and
- application/x-pkcs7-certreqresp gained magic. Pkcs7Parser further refines
- the smime-type on the output Content-Type. Files that detected as
- application/octet-stream in 3.x may now detect as a crypto type
- (TIKA-1997, TIKA-2856).
-
* tika-pipes gains three parse modes: NO_PARSE (detect only, no parse),
CONTENT_ONLY (emitters write raw content, no metadata envelope) and
UNPACK (write embedded bytes out). All three are wired through tika-app
@@ -308,22 +441,72 @@ Release 4.0.0 - ???
tika-parser-tess4j-module adds in-process Tesseract OCR
(TIKA-4665, TIKA-4666, TIKA-4667, TIKA-4690).
+ * Unified XMP extraction across containers; adds HEIF/HEIC and WebP XMP,
+ including Samsung/Google Motion Photo (TIKA-4775).
+
+ * tika-app and tika-server can load extra jars (additional
EncodingDetectors,
+ Parsers, etc.) from the directory named by the -Dtika.extras.dir system
+ property, without repackaging the application. Off by default; the
+ directory is a trusted code location whose contents run with full process
+ privileges. The jars are forwarded onto forked pipes/server workers too,
+ so they are available where parsing happens (TIKA-4755).
+
* A Markdown parser with structured, lossless XHTML output, complementing
the Markdown content handler (TIKA-4770).
+ * Content-based detection of ASN.1/DER crypto containers, enabled by
+ default: the PKCS#7/CMS, PKCS#12 and RFC 5544 timestamped-data families
+ gained magic where 3.x had globs only, and Pkcs7Parser refines the
+ smime-type on the output Content-Type at parse time. Files that detected
+ as application/octet-stream in 3.x may now detect as a crypto type; see
+ configuration/detectors.adoc for the opt-in detect-time refinement
+ (TIKA-1997, TIKA-2856).
+
* New detection: Android binary XML (application/vnd.android.axml,
TIKA-4747) and Frictionless Data packages (TIKA-4643); improved mp3/aac
(TIKA-4612) and grib (TIKA-4655) detection.
OTHER CHANGES
- * Dependency upgrades since 4.0.0-beta-1, including Jetty 12.1.12, CXF
- 4.2.3 and SolrJ 10.0.0 (TIKA-4327).
+ * Release artifacts are now channel-specific. Maven Central gets slim
+ per-module jars (plus pom, sources and javadoc); the Apache dist area
+ gets runnable zip distributions (tika-app, tika-server-standard,
+ tika-eval-app) and drop-in pf4j plugin zips; Docker Hub gets ready-to-run
+ images. Fat/shaded artifacts no longer go to Maven Central (TIKA-4733).
* The charset, junk-text and language detection stack was rewritten:
language-aware charset detection, a universal junk detector, wider
- Unicode handling and the new CharSoup language detector
- (TIKA-4662, TIKA-4671, TIKA-4675, TIKA-4691, TIKA-4719, TIKA-4810).
+ Unicode handling, the new CharSoup language detector, and more efficient
+ common-token lookups via bloom filters (TIKA-4662, TIKA-4671, TIKA-4675,
+ TIKA-4691, TIKA-4719, TIKA-4731, TIKA-4745, TIKA-4754, TIKA-4810).
+
+ * Pipes now carries small documents to the forked worker inside the request
+ instead of writing them to disk first. Content at or below the new
+ pipes.maxInlineBytes (default 10 MB) rides in the request and is served in
+ the worker by the reserved __bytes fetcher, touching no disk; larger
+ content is written out once as before, and a stream already backed by a
+ file keeps its file. Set maxInlineBytes to 0 to spool every non-empty body
+ (TIKA-4808).
+
+ * PipesClient/PipesServer IPC now enforces a configurable payload limit
+ (pipes.maxIpcPayloadBytes, default 100 MB) in both directions. Results
+ that exceed the limit return PAYLOAD_LIMIT_EXCEEDED instead of causing
+ heap exhaustion; crash messages are also size-capped (TIKA-4793).
+
+ * tika-server requests now carry only their own parse-context entries to the
+ forked worker, which supplies the config defaults itself. Previously the
+ server sent its config's parse-context with every request, so the worker
+ treated the operator's timeout-limits as caller input and clamped them at
+ pipes.maxTotalTaskTimeoutMillis (TIKA-4808).
+
+ * tika-grpc now routes fetchAndParse through the PipesParser client pool
+ instead of one shared single-threaded PipesClient: concurrent calls no
+ longer crash the worker, pipes.numClients and (for the first time)
+ pipes.useSharedServer take effect, and pool saturation surfaces in-band as
+ CLIENT_UNAVAILABLE_WITHIN_MS. An interrupted call recycles its worker, so
a
+ pooled client cannot go back to the queue dirty (TIKA-4815).
+ fetchAndParseServerSideStreaming now completes the call after delivering
+ its reply, instead of leaving the client waiting forever (TIKA-4804).
* New audio/video metadata: audio:bitrate, audio:is-variable-bitrate,
audio:has-drm, audio:channels, video:frame-rate, video:bitrate and MP4
@@ -341,153 +524,33 @@ Release 4.0.0 - ???
MAPI properties no longer overwrite better-fitting Dublin Core terms
(TIKA-4806). Embedded-file naming was streamlined (TIKA-4689).
- * tika-eval-core is no longer published as a fat jar (TIKA-4414) and
- tika-grpc no longer shades gRPC (TIKA-4709).
-
- * PipesClient/PipesServer IPC now enforces a configurable payload limit
- (pipes.maxIpcPayloadBytes, default 100 MB) in both directions. Results
- that exceed the limit return PAYLOAD_LIMIT_EXCEEDED instead of causing
- heap exhaustion; crash messages are also size-capped (TIKA-4793).
-
- * Pipes now carries small documents to the forked worker inside the request
- instead of writing them to disk first. A host that already holds the
- content -- tika-server's /tika, /rmeta, /meta, /detect and /unpack, or
- PipesForkParser with a non-file-backed stream -- sends anything at or
- below the new pipes.maxInlineBytes (default 10 MB) in the request, where
- the reserved __bytes fetcher serves it in the worker and no disk is
- touched; larger content is written out once as before (to tika-server's
- input temp directory, or the calling JVM's java.io.tmpdir under
- PipesForkParser), and a stream already backed by a file always keeps its
- file. Set maxInlineBytes to 0 to spool every non-empty body. The value
must
- leave room for the rest of the request inside pipes.maxIpcPayloadBytes;
- one that does not is rejected at config load (TIKA-4808).
+ * PDFs whose %PDF- header is preceded by a print-composition job ticket are
+ no longer detected as text/x-matlab: up to 50 %% comment or blank lines
may
+ now precede it, extending the TIKA-3328 rule past its 512-byte reach
+ (TIKA-4782).
* MagicDetector now compiles its regular expression once, in the
constructor, instead of recompiling it on every match (TIKA-4796).
- * Unified timeout model across the library, pipes, and server: a total-task
- budget plus a progress/stall timeout, composed recursively over embedded
- documents (TIKA-4813).
-
- * tika-server: /meta now runs through the same pipes-backed parser as the
- other extraction endpoints (TIKA-4809).
+ * tika-eval-core is no longer published as a fat jar (TIKA-4414) and
+ tika-grpc no longer shades gRPC (TIKA-4709).
- * tika-server requests now carry only their own parse-context entries to the
- forked worker, which supplies the config defaults itself. Previously the
- server sent its config's parse-context along with every request, so the
- worker -- which clamps request-supplied timeout limits but trusts its own
- config's -- treated the operator's timeout-limits as caller input and
- clamped them at pipes.maxTotalTaskTimeoutMillis (TIKA-4808).
-
- * tika-grpc's fetchAndParseServerSideStreaming now completes the call
- after delivering its reply, instead of leaving the client waiting
- for a terminal signal that never came (TIKA-4804).
-
- * tika-grpc now routes fetchAndParse through the PipesParser client
- pool instead of one shared single-threaded PipesClient: concurrent
- calls no longer crash the worker, pipes.numClients and (for the
- first time) pipes.useSharedServer take effect, up to numClients
- forked worker JVMs instead of one, and pool saturation surfaces
- in-band as CLIENT_UNAVAILABLE_WITHIN_MS. An interrupted call
- closes its connection and recycles the per-client worker, so a
- pooled client cannot go back to the queue dirty (TIKA-4815).
+ * Fix concurrency bug in TikaToXMP (TIKA-4393).
- * PDFs whose %PDF- header is preceded by a print-composition job ticket are
- no longer detected as text/x-matlab. Up to 50 %% comment or blank lines of
- up to 150 characters, and nothing else, may now precede the header; the
- TIKA-3328 rule this extends only reached 512 bytes (TIKA-4782).
+ * Dependency upgrades throughout the 4.0.0 line, including Jetty 11 ->
+ 12.1.12, CXF 4.0 -> 4.2.3 and SolrJ 8.11.4 -> 10.0.0, plus routine
+ library updates (TIKA-4327).
Release 4.0.0-beta-1 - 6/29/2026
- BREAKING CHANGES
-
- * The default content handler is now Markdown. tika-app, tika-server
- (the /tika and /rmeta endpoints), and the async/pipes CLI now emit
- Markdown content by default instead of XHTML/XML (plain text for the
- async CLI). Request the previous format explicitly, e.g. tika-app
- -x/--xml, the server /tika/xml and /rmeta/xml paths (or the
- X-Tika-Handler header), and the async CLI --handler x (TIKA-4663).
-
- NEW FEATURES
-
- * tika-app and tika-server can load extra jars (additional
EncodingDetectors,
- Parsers, etc.) from the directory named by the -Dtika.extras.dir system
- property, without repackaging the application. Off by default; the
directory
- is a trusted code location whose contents run with full process
privileges.
- The extra jars are also forwarded onto forked pipes/server worker
processes,
- so they are available where parsing actually happens (TIKA-4755).
-
- * More granular, default-deny capability flags for tika-server and
tika-grpc.
- tika-server's enableUnsecureFeatures is split into allowPipes (gates the
- /pipes and /async endpoints) and allowPerRequestConfig (gates the /config
- endpoints and the multipart config part); the /status endpoint is no
longer
- gated and is enabled simply by listing it under endpoints. tika-grpc gains
- the same allowPerRequestConfig flag plus allowComponentModifications
(gates
- runtime Save/Delete of fetchers and pipes iterators). All flags default to
- false, so an out-of-the-box tika-grpc server no longer accepts per-request
- configuration or runtime store mutations (TIKA-4764).
-
- * Unified XMP extraction across containers; adds HEIF/HEIC and WebP XMP,
- including Samsung/Google Motion Photo (TIKA-4775).
-
- OTHER CHANGES
-
- * Release artifacts are now channel-specific. Maven Central gets slim
- per-module jars (plus pom, sources and javadoc); the Apache dist area
- gets runnable zip distributions (tika-app, tika-server-standard,
- tika-eval-app) and drop-in pf4j plugin zips; Docker Hub gets ready-to-run
- images. Fat/shaded artifacts no longer go to Maven Central, and release
- staging is validated so a missing artifact fails the build (TIKA-4733).
-
- * Improved charset (encoding) detection and junk/garbage-text detection,
- including more efficient common-token lookups via bloom filters
- (TIKA-4731, TIKA-4745, TIKA-4754).
-
- * Dependency upgrades, including Jetty 11 -> 12.0.36,
- CXF 4.0 -> 4.1.7, plus routine library updates (TIKA-4327).
+ Prerelease. Its changes are folded into the 4.0.0 section above.
Release 4.0.0-alpha-1 - 5/4/2026
- BREAKING CHANGES
-
- * Move from xml to json based configuration (TIKA-4544 and many others).
-
- * tika-pipes implementation modules have been reorganized by
- resource (tika-pipes-solr) vs task (tika-pipes-fetcher-solr)
- (TIKA-4543). Note that the file-system pipes components have
- been taken out of tika-pipes-core and placed in their own
- pf4j module: tika-pipes-file-system.
-
- * tika-pipes implementation modules are now pf4j plugins (TIKA-4519).
-
- * tika-pipes core classes have been moved to a new module: tika-pipes-core,
- and the FileSystem pipes components have moved (TIKA-4334).
-
- * MetadataListFilter has been renamed MetadataFilter, and
- MetadataFilter has been removed (TIKA-4546).
-
- * Removed several modules, including: tika-batch (TIKA-4333), snaps
deployment (TIKA-4502),
- dotnet (TIKA-4332), advanced media module (TIKA-4500), tika-dl module
(TIKA-4499),
- tika-fuzzing module (TIKA-4506).
-
- * Headers are no longer injected into the body/content of MSG files
(TIKA-4345). Please open
- a ticket if you need this behavior across email formats.
-
- * API changes in the EmbeddedStreamTranslator (TIKA-4518).
-
- * Removed DigestingParser (TIKA-4607).
-
- * tika-parsers-standard-package is now a pom, not a jar.
- Users must add <type>pom</type> in Maven or @pom in Gradle (TIKA-4712).
-
- * Removed legacy ExternalParser; external parsers now require explicit
- JSON configuration (TIKA-4707).
-
- OTHER CHANGES
+ Prerelease. Its changes are folded into the 4.0.0 section above.
- * Fix concurrency bug in TikaToXMP (TIKA-4393)
Release 3.3.0 - 3/18/2026
diff --git a/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
b/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
index 4d29063ab9..3c0cb71dde 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc
@@ -56,9 +56,11 @@ try (TikaInputStream tis =
TikaInputStream.get(myInputStream)) {
----
The `Tika` facade (`Tika#parse`, `Tika#parseToString`, `Tika#detect`) still
accepts a plain
-`InputStream`. One behavior change: `Tika#detect(InputStream, ...)` no longer
resets the stream
-to its original position — treat the stream as consumed after the call. It
still does not close
-the caller's stream.
+`InputStream`. One behavior change: `Tika#detect(InputStream, ...)` no longer
returns the
+caller's stream at its original position. The detector still resets the
`TikaInputStream` it
+reads — but that read-ahead is buffered inside an internal wrapper that
`detect()` discards, so
+the caller's own stream comes back advanced. Pass a `TikaInputStream` you own
(and rewind it),
+or re-open the source. The stream is still not closed for you.
Why: passing `TikaInputStream` explicitly makes the spooling and rewind
contract visible in the
signature instead of leaving every implementation to wrap defensively. See