Introduction
When a legal department receives multiple contract PDFs, each reviewer often adds their own password to protect confidential clauses. Consolidating these files into a single binder becomes a nightmare because the passwords differ and the files cannot be merged directly. Manual decryption is time‑consuming and error‑prone, especially when dealing with dozens of PDFs.
Password‑merge is a GroupDocs.Merger workflow for Java that unlocks heterogeneous PDFs and re‑protects the merged result with a single credential. This tutorial walks through detecting protected PDFs, unlocking them, merging the content, and optionally rotating the unified password.
You’ll learn how to configure the Merger API, process byte streams, and generate a secure combined PDF in under 30 lines of Java code.
When should I merge password‑protected PDFs?
Merging password‑protected PDFs makes sense whenever you need a single, searchable archive that respects security policies while eliminating the overhead of handling multiple passwords. Typical scenarios include quarterly financial report bundles, contract binders for audits, and legal case files where each contributor applied a different password. By unlocking each file programmatically and applying a unified password, you keep the archive secure and simplify downstream review processes. The whole operation can be automated in a CI pipeline, saving hours of manual work.
Prerequisites
- Java 11 or later
- GroupDocs.Merger for Java 24.6+ (temporary license)
- A set of PDF files, each optionally paired with its password
Install the library via Maven:
mvn dependency:copy -Dartifact=com.groupdocs:groupdocs-merger:24.6
Step 1 – Detect if a PDF is password‑protected
Before attempting to unlock a file, check whether it actually carries a password. This avoids unnecessary processing and lets you log which files need credentials.
// Returns true if the PDF at `path` has an owner or user password
public boolean isDocumentProtected(String path, String password) {
Merger merger;
if (password == null || password.isEmpty()) {
merger = new Merger(path);
} else {
merger = new Merger(path, new LoadOptions(password));
}
try {
return merger.isPasswordSet();
} finally {
merger.dispose();
}
}
Key points:
LoadOptionscarries a known password; if none is provided the file is opened normally.isPasswordSet()reports true for both owner and user passwords.- Always dispose the
Mergerinstance to free native resources.
Step 2 – Unlock each PDF and collect raw bytes
Iterate over a map where the key is the file path and the value is its password (null if none). The method returns a list of byte arrays representing the unlocked PDFs.
public List<byte[]> unlockAll(Map<String, String> sources) throws IOException {
List<byte[]> unlocked = new ArrayList<>();
for (Map.Entry<String, String> e : sources.entrySet()) {
String path = e.getKey();
String password = e.getValue();
System.out.println("Unlocking (credentials=" +
(password != null ? "yes" : "no") + "): " + path);
if (password == null || password.isEmpty()) {
unlocked.add(Files.readAllBytes(Paths.get(path)));
} else {
LoadOptions opts = new LoadOptions(password);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Merger m = new Merger(path, opts);
try {
m.removePassword();
m.save(buf);
} finally {
m.dispose();
}
unlocked.add(buf.toByteArray());
}
}
return unlocked;
}
Key points:
removePassword()strips the existing protection.- The decrypted content is written to a
ByteArrayOutputStreamfor in‑memory handling. - Files without a password are read directly to keep the flow simple.
Step 3 – Merge the unlocked PDFs and apply a unified password
Create a Merger from the first PDF stream, then join the remaining streams. Finally, protect the combined document with AddPasswordOptions.
public void mergeAndProtect(List<byte[]> unlockedPdfs,
String unifiedPassword,
String outputPath) {
InputStream first = new ByteArrayInputStream(unlockedPdfs.get(0));
Merger merger = new Merger(first);
try {
for (int i = 1; i < unlockedPdfs.size(); i++) {
merger.join(new ByteArrayInputStream(unlockedPdfs.get(i)));
}
merger.addPassword(new AddPasswordOptions(unifiedPassword));
merger.save(outputPath);
} finally {
merger.dispose();
}
System.out.println("Merged output: " + new File(outputPath).getAbsolutePath());
System.out.println("Unified password: " + unifiedPassword);
}
Key points:
addPasswordencrypts the final PDF with the supplied credential.- All operations happen in memory; only the final file is written to disk.
- Dispose the
Mergerto release native handles.
Step 4 – Rotate the password on an already‑protected PDF (optional)
If your organization enforces periodic password rotation, you can update the credential without re‑merging the source files.
public void rotateUnifiedPassword(String path,
String oldPassword,
String newPassword,
String outputPath) {
Merger merger = new Merger(path, new LoadOptions(oldPassword));
try {
merger.updatePassword(new UpdatePasswordOptions(newPassword));
merger.save(outputPath);
} finally {
merger.dispose();
}
System.out.println("Rotated output: " + new File(outputPath).getAbsolutePath());
System.out.println("New password: " + newPassword);
}
Key points:
- Load the protected PDF with the current password.
updatePasswordreplaces it with the new credential.- This operation is fast because it does not re‑process the PDF content.
Real‑World Application
I hit this when consolidating five investor contracts that each had a different reviewer password. Using the steps above, I unlocked all files, merged them into a single binder, and applied a single password that matched our corporate policy. The whole process ran in under two minutes on a standard laptop.
Best Practices
- Validate passwords early: Use
isDocumentProtectedto flag files that may need manual attention. - Limit memory usage: For large PDFs, stream them to disk instead of keeping all byte arrays in memory.
- Dispose objects promptly: The Merger class holds native resources; always call
dispose()in afinallyblock. - Use a temporary license only for development; obtain a production license before release.
Conclusion
GroupDocs.Merger for Java provides a clean API for unlocking, merging, and re‑securing PDF collections. By following the four steps—detecting protection, unlocking, merging with a unified password, and optionally rotating that password—you can automate the creation of secure PDF binders without manual intervention.
Next steps:
- Explore additional options such as setting PDF metadata after merge (documentation).
- Learn how to merge PDFs while preserving bookmarks (API reference).
- Check out the full sample project on GitHub for a ready‑to‑run implementation.