Getting Started with the Tika Facade
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Baseline date: 2026-10-12. This page was written against Apache Tika 4.1.0 (the latest release on Maven Central on that
date) with the 3.3.x differences noted, Java 21 and later for the examples (Tika 4.x needs Java 17), Spring Boot 4.x on
Spring Framework 7 and the Docker image apache/tika:4.1.0. The org.apache.tika.Tika class is the shortest path
from a file to its media type and text: a facade over DefaultDetector and AutoDetectParser with a handful of
convenience methods. This page shows each method, its limits and its traps, and builds the first program of the
Bookshelf scenario around it, on manuscript.docx and catalogue.pdf. Add the dependencies from
Setup & Installation first (tika-core and
tika-parsers-standard-package with <type>pom</type>); the pieces behind the facade are described in
Introduction & Architecture.
All examples on this page were compiled and run against Tika 4.1.0 with small stand-in files: a one-heading
manuscript.docx titled "The Lighthouse Keeper" by Ana Torres, and a one-page catalogue.pdf titled "Spring
catalogue". The real Bookshelf files are larger, so character counts will differ.
What the facade offers
| Method | What it does | Notes |
|---|---|---|
|
Returns the media type as a string such as |
|
|
The same, with a file name or full metadata as a hint. |
The stream can be |
|
Parses the document and returns its plain text as one |
Limited to |
|
Returns a |
The reader closes the underlying stream; a background thread fills it. |
|
Translates text with the translator the facade was built with. |
Needs an external service; see Language Detection & Translation. |
|
Configuration and access to the wrapped components. |
|
Source: Tika facade, Javadoc 4.1.0.
The default constructor new Tika() uses new DefaultDetector() and new AutoDetectParser(): every detector and
parser found on the classpath is available. There is no constructor that takes a configuration object in 4.x. To use a
JSON configuration, build the detector and parser with TikaLoader (from tika-serialization) and pass them to
new Tika(detector, parser); see the section below on outgrowing the facade.
Detecting the media type
detect answers the first Bookshelf question: what is this file? Detection reads the first bytes (magic), inspects
containers (an OOXML file is a ZIP; an old .doc is an OLE2 file) and uses the file name as a hint.
import java.io.IOException;
import java.nio.file.Path;
import org.apache.tika.Tika;
public class DetectOnly {
public static void main(String[] args) throws IOException {
Tika tika = new Tika();
System.out.println(tika.detect(Path.of("manuscript.docx")));
System.out.println(tika.detect(Path.of("catalogue.pdf")));
System.out.println(tika.detect(Path.of("renamed-invoice.png")));
System.out.println(tika.detect("notes.txt"));
}
}
Output (with renamed-invoice.png being a copy of the PDF):
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/pdf
application/pdf
text/plain
The renamed file is reported as application/pdf, because the content wins over the misleading extension. The last
call passes only a name, so the answer is a guess from the extension; never trust name-only detection for uploads.
Media types, the detection pipeline and custom types are covered in the
Media Types & Detection page of
this section.
The stream-position change in 4.x
detect(InputStream) reads ahead to look at the magic bytes. In Tika 3.x it left a mark-supporting caller stream at its
original position. In 4.x it does not: detection runs through an internal TikaInputStream wrapper that is discarded,
so the caller’s stream comes back advanced. The Javadoc states it: treat the stream as consumed.
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.tika.Tika;
import org.apache.tika.io.TikaInputStream;
public class StreamPosition {
public static void main(String[] args) throws IOException {
Tika tika = new Tika();
Path pdf = Path.of("catalogue.pdf");
try (InputStream in = Files.newInputStream(pdf)) {
String type = tika.detect(in);
System.out.println(type + ", bytes left on the caller's stream: " + in.readAllBytes().length);
}
try (TikaInputStream tis = TikaInputStream.get(pdf)) {
String type = tika.detect(tis);
tis.rewind();
System.out.println(type + ", bytes left after rewind: " + tis.readAllBytes().length);
}
}
}
Output for the 785-byte sample PDF:
application/pdf, bytes left on the caller's stream: 0
application/pdf, bytes left after rewind: 785
The rule for new code: detect and then read the same data only with a TikaInputStream that you own and rewind(),
or reopen the source. Passing the same raw stream to detect and then to parseToString means the parser no longer sees the whole
document.
Extracting text with parseToString
parseToString runs AutoDetectParser with a BodyContentHandler and returns the body text.
import java.io.IOException;
import java.nio.file.Path;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
public class TextOnly {
public static void main(String[] args) throws IOException, TikaException {
Tika tika = new Tika();
String text = tika.parseToString(Path.of("manuscript.docx"));
System.out.println(text.strip());
}
}
Output:
The Lighthouse Keeper
Chapter one begins at dusk.
Four properties of this method matter in production.
-
Plain text, not Markdown. The facade returns text; the Markdown default of 4.x applies to
tika-app,tika-serverand Tika Pipes, not toparseToString. Use a content handler for other formats (see Content Handlers & Output Formats). -
A length limit that does not raise an error. The result is cut at
getMaxStringLength()characters, 100,000 by default, to avoid out-of-memory errors on huge documents. When the limit is reached the method returns what it has and says nothing; a very long manuscript is truncated silently. Raise it withsetMaxStringLength(int), or pass-1to disable it for trusted input only. -
The stream is closed for you. Unlike most Tika methods,
parseToString(InputStream)closes the stream. With aPath,FileorURLthe facade opens and closes the resource itself. -
The text is not trimmed. The PDF of the sample starts with a newline; call
strip()before displaying or hashing.
The effect of the limit can be seen with a tiny value:
Tika small = new Tika();
small.setMaxStringLength(10);
System.out.println("[" + small.parseToString(Path.of("catalogue.pdf")) + "]");
Output:
[
Bookshelf]
Metadata out-parameters
The overloads that take a Metadata object fill it with what the parser found. The same object is also an input: the
file name and a declared content type steer detection.
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.HttpHeaders;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
public class TextAndMetadata {
public static void main(String[] args) throws IOException, TikaException {
Tika tika = new Tika();
Metadata metadata = new Metadata();
try (InputStream in = Files.newInputStream(Path.of("manuscript.docx"))) {
String text = tika.parseToString(in, metadata);
System.out.println(text.strip().length() + " characters");
}
System.out.println("title: " + metadata.get(TikaCoreProperties.TITLE));
System.out.println("creator: " + metadata.get(TikaCoreProperties.CREATOR));
System.out.println("type: " + metadata.get(HttpHeaders.CONTENT_TYPE));
}
}
Output:
49 characters
title: The Lighthouse Keeper
creator: Ana Torres
type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Notes on the keys:
-
TikaCoreProperties.TITLEandCREATORare normalised keys: whatever the format calls them (Dublin Coredc:titlein OOXML, the Info dictionary in PDF), the parser also writes them under the common names. -
HttpHeaders.CONTENT_TYPEis aPropertyin 4.x, andMetadatano longer re-exports it. Code copied from the 1.x book or a 3.x tutorial that saysMetadata.CONTENT_TYPEdoes not compile; useHttpHeaders.CONTENT_TYPEor the string"Content-Type". -
Format-specific keys are present too. For the sample PDF, a run also reported
pdf:docinfo:title,pdf:producer,xmpTPg:NPages,tk:parsed-byand manyaccess-permission:*keys. Tika-asserted keys are under thetk:prefix in 4.x (they wereX-TIKA:in 3.x). The Metadata page of this section lists them.
parse: a Reader for streamed text
parse returns a java.io.Reader that yields the text as the parser produces it. It suits a consumer that streams the
text to a file, a hash, or an indexer without building one large string.
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Path;
import org.apache.tika.Tika;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
public class StreamedText {
public static void main(String[] args) throws IOException {
Tika tika = new Tika();
Metadata metadata = new Metadata();
try (Reader reader = tika.parse(Path.of("catalogue.pdf"), metadata)) {
char[] buffer = new char[1000];
int read = reader.read(buffer);
System.out.println("read " + read + " characters; title=" + metadata.get(TikaCoreProperties.TITLE));
}
}
}
Output:
read 72 characters; title=Spring catalogue
Rules for the reader:
-
Always close it, with try-with-resources. Closing the reader closes the underlying stream and stops the parser.
-
A background thread parses. The reader is a
ParsingReader, and the parser runs on its own thread. Metadata is filled while the parser runs, so read it after you have consumed the text if you want all the keys. -
No length limit applies.
setMaxStringLengthaffects onlyparseToString; withparse, you decide how much to read. Failures are reported while you read, so keep the read loop inside the same try-with-resources block.
Errors
-
A missing or unreadable file throws
java.io.IOException(NoSuchFileExceptionin a run with a missing path). -
A document that cannot be parsed throws
org.apache.tika.exception.TikaException. Amanuscript.docxtruncated to its first 300 bytes is still detected as a Word document, butparseToStringthrowsTikaException: Error opening OOXML file. The underlying XML parser also logs a fatal-level line, which is noise, not a second failure. -
Encrypted documents and unsupported content raise their own
TikaExceptionsubclasses; the Parser API & AutoDetectParser and Configuration pages cover them.
Catch TikaException per document in a batch so that one broken file does not stop the run, as the first program below
does.
Thread safety and reuse
A Tika object holds only its detector, parser, translator and the maximum string length. The common and tested use is
to create one instance and share it. A run with 200 parses of the two sample files on a pool of 8 threads, all through
one Tika instance, returned the expected media type and text length every time.
-
Create the instance once (a field, a Spring bean) and reuse it. Creating
new Tika()per request is wasteful: it builds a detector and a parser every time. -
Call
setMaxStringLengthduring start-up, before sharing the instance: the field is a plainintand is not synchronised, so changing it while other threads parse is a data race. -
Share the facade, never the streams, readers or
Metadataobjects: create those per document. -
This is the thread safety of the facade only. Parsers run in your JVM; for isolation from crashes and hangs use
PipesForkParseror a service, as described in Introduction & Architecture.
First Bookshelf program
The program below scans an inbox directory and reports, for every file, the detected type, the title and author found in the file, and the size and beginning of the extracted text. It handles errors per file, limits the text length, and never trusts file names.
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
public class BookshelfIntake {
private static final Tika TIKA = new Tika();
static {
TIKA.setMaxStringLength(200_000);
}
public static void main(String[] args) throws IOException {
Path inbox = Path.of(args.length > 0 ? args[0] : "inbox");
try (Stream<Path> files = Files.list(inbox)) {
for (Path file : files.sorted().toList()) {
describe(file);
}
}
}
static void describe(Path file) throws IOException {
String mediaType = TIKA.detect(file);
Metadata metadata = new Metadata();
String text;
try (InputStream in = Files.newInputStream(file)) {
text = TIKA.parseToString(in, metadata);
} catch (TikaException e) {
System.out.printf("%s -> %s: cannot parse (%s)%n", file.getFileName(), mediaType, e.getMessage());
return;
}
String clean = text.strip().replaceAll("\\s+", " ");
System.out.printf("%s -> %s%n", file.getFileName(), mediaType);
System.out.printf(" title: %s%n", metadata.get(TikaCoreProperties.TITLE));
System.out.printf(" creator: %s%n", metadata.get(TikaCoreProperties.CREATOR));
System.out.printf(" chars: %d%n", text.length());
System.out.printf(" start: %s%n", clean.substring(0, Math.min(50, clean.length())));
}
}
With manuscript.docx, catalogue.pdf and a copy of the PDF named renamed-invoice.png in inbox/, a run printed:
catalogue.pdf -> application/pdf
title: Spring catalogue
creator: Bookshelf Press
chars: 72
start: Bookshelf spring catalogue Forty titles from indep
manuscript.docx -> application/vnd.openxmlformats-officedocument.wordprocessingml.document
title: The Lighthouse Keeper
creator: Ana Torres
chars: 50
start: The Lighthouse Keeper Chapter one begins at dusk.
renamed-invoice.png -> application/pdf
title: Spring catalogue
creator: Bookshelf Press
chars: 72
start: Bookshelf spring catalogue Forty titles from indep
The program accepts three different inputs through one code path, reads metadata from two unrelated file formats with the same two keys, and sees through the renamed PDF. It also shows what is missing for production: it parses in the application’s own JVM, reads the whole text into memory, ignores embedded documents (a PDF attachment or a ZIP inside an e-mail would be skipped), has no timeout and has no encoding or language handling.
When to outgrow the facade
| Need | Move to |
|---|---|
Text as XHTML, Markdown or only part of the document, or a |
|
Embedded documents, attachments, one record per part |
|
A JSON configuration: custom parsers, OCR, limits, metadata filters |
|
Hostile input, parse timeouts, memory limits |
|
Many files, from storage systems, into a search index |
Tika Pipes with fetchers and emitters. |
A first step beyond the facade keeps its convenience and takes its parts from a loader. The detector and parser come
from the default JSON configuration, and the facade only wraps them (compiled and run on 4.1.0 with
tika-serialization added):
import java.nio.file.Path;
import org.apache.tika.Tika;
import org.apache.tika.config.loader.TikaLoader;
public class LoadedFacade {
public static void main(String[] args) throws Exception {
TikaLoader loader = TikaLoader.loadDefault();
Tika tika = new Tika(loader.loadDetectors(), loader.loadAutoDetectParser());
System.out.println(tika.detect(Path.of("catalogue.pdf")));
System.out.println(tika.parseToString(Path.of("catalogue.pdf")).strip());
}
}
Output:
application/pdf
Bookshelf spring catalogue
Forty titles from independent publishers.
TikaLoader.loadDefault() loads the default configuration; the Configuration page shows how
to load a
tika-config.json instead.
From the book to 4.x
| Book (1.x) and 3.x idiom | 4.x |
|---|---|
|
No |
|
|
|
The stream is advanced; use a |
|
|
|
Still valid for trusted input; use pipes or a service for untrusted files. |
Source: Migrating to Tika 4.x.
Checklist
-
One shared
Tikainstance; setsetMaxStringLengthonce at start-up. -
Treat
detect(InputStream)as consuming the stream; useTikaInputStreamplusrewind()to read it again. -
Know that the default limit is 100,000 characters and that truncation is silent.
-
Close every
Readerfromparse; catchTikaExceptionper document. -
Read metadata through
TikaCorePropertiesandHttpHeadersconstants, not removedMetadatafields. -
Do not use the facade on untrusted files in a critical JVM; use a forked or service parser.