| Lesson 8 | Jakarta EE Packaging and Deployment Descriptors |
| Objective | Explain how Jakarta EE 11 applications use WAR, JAR, and EAR modules with annotations and optional deployment descriptors. |
A Jakarta EE application is delivered as one or more standard deployment units. Each unit has a defined purpose and directory layout, allowing a compatible runtime to discover application components, libraries, resources, and configuration. The most familiar units are Java archives, web archives, and enterprise archives, identified by the .jar, .war, and .ear filename extensions.
Early Enterprise Beans applications depended heavily on XML files that described every component. Modern Jakarta EE uses annotations, naming conventions, and default discovery rules for most deployment metadata. Standard XML deployment descriptors still exist, but they are commonly optional. They are most useful when configuration belongs outside source code, when an assembler must override component metadata, or when a module deliberately disables annotation scanning.
A module is a deployable collection of components for a particular container. An archive is the packaged file that carries a module or application. Although WAR and EAR files use the same ZIP-compatible archive format as a JAR, their extensions and internal layouts tell the runtime how to interpret them.
| Archive | Module or application role | Typical contents |
|---|---|---|
| JAR | Java library or stand-alone Jakarta Enterprise Beans module | Compiled classes, resources, and optional META-INF descriptors |
| WAR | Web module and, often, a complete application | Servlets, Jakarta REST resources, JSP pages, web resources, classes, and libraries |
| EAR | Enterprise application assembled from several modules | WAR and JAR modules, shared libraries, and optional application metadata |
| RAR | Jakarta Connectors resource-adapter module | Connector implementation, dependencies, and resource-adapter metadata |
An application does not need an EAR simply because it uses Jakarta EE. A single WAR can contain an entire web application, including Enterprise Beans when it is deployed to a runtime that supports those components in web modules. EAR packaging is appropriate when several modules need to be assembled and deployed as one application.
The diagram emphasizes two design facts. First, each archive has a standardized structure. Second, XML descriptors are options within those structures, not separate files required for every component. Annotations and conventions usually supply the initial deployment model.
A WAR contains public web resources at its root and protected application material under WEB-INF. A browser can request a root resource such as a JSP page or image, subject to application rules. It cannot directly retrieve files under WEB-INF. The runtime can still load classes, libraries, and descriptors from that protected directory.
store.war
|-- index.jsp
|-- images/
| +-- logo.png
+-- WEB-INF/
|-- classes/
| +-- com/example/store/CartResource.class
|-- lib/
| +-- application-library.jar
|-- web.xml
+-- beans.xml
WEB-INF/classes is a classpath location for compiled application classes and resources. Library JARs belong in WEB-INF/lib. The optional WEB-INF/web.xml descriptor can declare servlets, filters, listeners, mappings, security constraints, error pages, and session configuration. Modern applications often use annotations such as @WebServlet and defaults instead.
WEB-INF/beans.xml is a standard location for a CDI bean archive descriptor in a WAR. Depending on how bean classes are packaged and annotated, CDI discovery can work without this file. When present, beans.xml can select a discovery mode and configure features defined by CDI. A library JAR can use META-INF/beans.xml.
A stand-alone Jakarta Enterprise Beans module is a JAR whose component and supporting classes are stored using their package paths. Standard module metadata belongs under META-INF.
services.jar
|-- com/example/store/OrderService.class
|-- com/example/store/InventoryService.class
+-- META-INF/
|-- ejb-jar.xml
+-- persistence.xml
META-INF/ejb-jar.xml is the optional Enterprise Beans deployment descriptor. It can declare components and assembly metadata, but it is not one descriptor per bean. A module containing classes annotated with @Stateless, @Stateful, @Singleton, or @MessageDriven can be discovered without this descriptor when annotation processing is enabled.
META-INF/persistence.xml defines persistence units when XML persistence-unit configuration is used. It can identify data sources, managed classes, mapping files, provider settings, and schema-generation behavior. The persistence descriptor configures Jakarta Persistence; it is not an Enterprise Beans component descriptor.
Modern Enterprise Beans do not require legacy creation or finder interfaces. A bean can expose a local business interface, a remote business interface when remote access is a genuine requirement, or a no-interface view. Packaging and business-view design are related deployment decisions, but they are not the same thing.
An EAR assembles modules that must be deployed as one enterprise application. A typical EAR might contain a web module, an Enterprise Beans module, and shared libraries:
store.ear
|-- web.war
|-- services.jar
|-- lib/
| +-- shared-domain.jar
+-- META-INF/
+-- application.xml
JAR files under the EAR lib directory are available as application libraries according to platform class-loading rules. The optional META-INF/application.xml descriptor gives a top-level view of the application modules and can define assembly information. When it is absent, the deployment tool uses default naming and module-discovery rules.
EAR packaging is valuable when module boundaries have operational or architectural meaning. It is unnecessary overhead for a small application that deploys cleanly as one WAR. Packaging should express the application structure, not imitate a larger architecture.
A deployment descriptor is standardized XML metadata associated with a module or application. Different specifications define different descriptor names, locations, schemas, and merge rules.
| Descriptor | Standard location | Purpose | Common modern use |
|---|---|---|---|
web.xml | WEB-INF/web.xml | Web components, mappings, security, sessions, and related web metadata | Optional when annotations and defaults are sufficient |
beans.xml | WEB-INF/beans.xml or applicable META-INF/beans.xml | CDI bean archive discovery and configuration | Included when explicit CDI archive configuration is needed |
ejb-jar.xml | META-INF/ejb-jar.xml | Enterprise Beans module metadata, assembly, and overrides | Optional for annotation-driven modules |
persistence.xml | META-INF/persistence.xml | Jakarta Persistence unit configuration | Used when persistence units are configured through XML |
application.xml | META-INF/application.xml in an EAR | Top-level enterprise application assembly | Optional when default module discovery is sufficient |
Optional does not mean obsolete. It means the same deployment information might be supplied through annotations or default rules. Some applications and specification features still need particular XML configuration. The relevant specification determines what may be omitted.
A standard deployment descriptor declares the Jakarta XML namespace, its descriptor version, and usually a schema location. The deployment tool validates the document against the schema selected by that declaration. A malformed document, an unsupported element, or an element in the wrong location must be treated as a deployment problem rather than silently guessed.
The version written in a descriptor identifies the schema used to interpret that XML file. It does not, by itself, declare the platform level used by every class in the application. A runtime can recognize descriptors from earlier specification generations for compatibility, while the surrounding application uses newer APIs. For a newly maintained Jakarta EE 11 application, prefer the current Jakarta namespace and the descriptor schema defined for the relevant component specification. Do not copy an old descriptor merely because the server accepts it.
Descriptor validation belongs in the build and deployment workflow. Source control should contain the XML, the build should package it at its standard path, and automated checks should catch schema or assembly mistakes before production deployment. This gives XML metadata the same repeatability expected from annotated Java source.
Annotations keep component metadata close to the Java type or method it describes. Descriptors keep metadata in the deployment unit, where an application assembler or deployer can review and adjust it independently of source code. Jakarta EE defines how the runtime combines these sources.
| Requirement | Annotation example | Descriptor alternative |
|---|---|---|
| Enterprise Bean type | @Stateless | Session component declaration in ejb-jar.xml |
| Transaction behavior | @TransactionAttribute | Container transaction elements in the assembly descriptor |
| Role-based access | @RolesAllowed | Security roles and method permissions |
| Resource dependency | @Resource | Resource reference elements |
| Servlet mapping | @WebServlet | Servlet and mapping elements in web.xml |
When a modern descriptor is present and annotation processing is enabled, the deployment tool logically merges descriptor information with discovered annotation metadata. Descriptor entries can override corresponding annotations according to the component specification. The merge produces the effective deployment model; it does not require the tool to write a new XML file.
A descriptor that supports metadata-complete can set that attribute to true. For the deployment metadata covered by that descriptor, the runtime then relies on the descriptor instead of scanning the module for corresponding deployment annotations. This setting is useful only when the descriptor actually provides a complete and intentional model. Setting it casually can make annotated components disappear from deployment.
XML remains useful when deployment policy should not be compiled into component classes. An assembler can centralize transaction or security rules, map resources for a target environment, configure components supplied by a library, or override annotation metadata without editing that library's source. Descriptors can also make a large module's effective configuration easier to audit.
Standard descriptors support portability between compatible products. A server-specific descriptor may configure clustering, product-specific naming, class loading, or tuning. Such files can be necessary in production, but their settings are not portable Jakarta EE contracts. Keep standard application metadata separate from vendor extensions and document why each extension is required.
The JDK jar tool can create, list, and extract archives, but production applications are normally packaged by Maven, Gradle, or an IDE that delegates to a build system. A build should compile source code, run tests, copy resources, resolve dependencies, and produce the same deployable layout whenever it is run from the same revision and configuration.
mvn clean package
gradle clean build
jar --list --file store.war
The resulting archive is the deployment input. Avoid manually adding files after the build, because that makes the deployed application difficult to reproduce and verify. Environment-specific values should come from supported configuration mechanisms instead of an unrecorded archive edit.
Tomcat 11 is a Servlet container and commonly deploys WAR files containing Jakarta Servlet, JSP, and related web application code. It is not a full Jakarta EE 11 Platform implementation. Plain Tomcat does not supply the complete Jakarta Enterprise Beans container, integrated full-platform transaction services, or the general EAR deployment model described in this lesson.
An application that needs those platform services should use a compatible Jakarta EE runtime. Selected libraries can add persistence, CDI, or other capabilities to a Tomcat application, but adding libraries does not turn Tomcat into a full-platform product. The deployment unit must match the services actually available in the selected runtime.
Jakarta EE 11 packaging is modular and annotation-friendly. WAR files carry web modules, JAR files carry libraries or stand-alone Enterprise Beans modules, and EAR files assemble multiple modules when that structure is warranted. Standard descriptors remain valuable, but they describe a module or application rather than one file per bean. Annotations, descriptors, and defaults combine into the effective deployment model, while reproducible build tools create the final archive. Choosing the smallest appropriate deployment unit keeps the application easier to build, deploy, and operate.