In Java, package-info.java is a special source file used to document and annotate an entire package rather than individual classes. It does not define any classes or interfaces; instead, it holds Javadoc comments and package-level annotations tied to the package declaration.

Why Package-Level Documentation Matters

As projects grow, the number of classes and interfaces increases, and understanding their relationships becomes harder. Class-level Javadoc explains individual types but often fails to describe the “big picture” of how they fit together, which is where package-level documentation becomes valuable.

By centralizing high-level information in package-info.java, teams can describe the purpose of a package, its design rules, and how its types should be used without scattering that information across many files.

The Structure of package-info.java

A typical package-info.java file contains three elements in this order:

  1. A Javadoc comment block that describes the package.
  2. Optional annotations that apply to the package as a whole.
  3. The package declaration matching the directory structure.

This structure makes the file easy to scan: documentation at the top, then any global annotations, and finally the declaration that links it to the actual package.

A Comprehensive Example

Imagine an application with a com.example.billing package that handles invoicing, payments, and tax calculations. A rich package-info.java for that package could look like this:

/**
 * Provides the core billing and invoicing functionality for the application.
 *
 * <p>This package defines:
 * <ul>
 *   <li>Immutable value types representing invoices, line items, and monetary amounts.</li>
 *   <li>Services that calculate totals, apply discounts, and handle tax rules.</li>
 *   <li>Integration points for payment providers and accounting systems.</li>
 * </ul>
 *
 * <h2>Design Guidelines</h2>
 * <ul>
 *   <li>All monetary calculations use a fixed-precision type and a shared rounding strategy.</li>
 *   <li>Public APIs avoid exposing persistence details; repositories live in a separate package.</li>
 *   <li>Domain objects are designed to be side‑effect free; state changes go through services.</li>
 * </ul>
 *
 * <h2>Thread Safety</h2>
 * <p>Value types are intended to be thread‑safe. Service implementations are stateless or guarded
 * by application-level configuration. Callers should not share mutable collections across threads.
 *
 * <h2>Usage</h2>
 * <p>Client code typically starts with the {@code InvoiceService} to create and finalize
 * invoices, then delegates payment processing to implementations of {@code PaymentGateway}.
 */
@javax.annotation.ParametersAreNonnullByDefault
package com.example.billing;

Note on the Annotation

The annotation @javax.annotation.ParametersAreNonnullByDefault used here is part of the JSR-305 specification, which defines standard Java annotations for software defect detection and nullability contracts. This particular annotation indicates that, by default, all method parameters in this package are considered non-null unless explicitly annotated otherwise.

Using JSR-305 annotations like this in package-info.java helps enforce global contract assumptions and allows static analysis tools (such as FindBugs or modern IDEs) to detect possible null-related errors more effectively.

Using Package-Level Annotations Effectively

Even without other annotations, package-info.java remains a powerful place to define global assumptions via annotations. Typical examples include nullness defaults from JSR-305, deprecation of an entire package, or framework-specific configuration.

By keeping only meaningful annotations, you avoid clutter while benefiting from centralized configuration.

When and How to Introduce package-info.java

The workflow for introducing package-info.java stays the same:

  1. Create package-info.java inside the target package directory.
  2. Write a clear Javadoc block that answers “what lives here” and “how it should be used.”
  3. Add only those package-level annotations that genuinely express a package-wide rule.
  4. Keep the file up to date whenever the package’s design or guarantees change.

With this approach, your package-info.java file becomes a concise, accurate source of truth about each package in your codebase, while clearly documenting the use of important annotations like those defined by JSR-305.