Class Loaders

This section strictly applies to Payara Server.

Payara Server extends the default JVM classloading and provides additional classes, which are loaded by the class loaders included by default on this distribution. Understanding Payara Server class loaders can help you determine where to place supporting JAR and resource files for your modules and applications.

Understanding Payara Server class loaders can help you determine where to place supporting JAR and resource files for your modules and applications.

In a JVM implementation, the class loaders dynamically load a specific Java class file needed for resolving a dependency. For example, when an instance of java.util.Enumeration needs to be created, one of the class loaders loads the relevant class into the environment.

For information about class loader debugging, see Class Loader Debugging.

Standard Classloading

In a JVM implementation, the class loaders dynamically load a specific Java class file needed for resolving a dependency. For example, when an instance of java.util.Enumeration needs to be created, one of the class loaders loads the relevant class into the environment.

For information about class loader debugging, see Class Loader Debugging.

Class loaders in Payara Server follow a delegation hierarchy by default.

The Class Loader Hierarchy

Class loaders in the Payara Server runtime follow a delegation hierarchy that is illustrated in the following table:

Class Loader Description

Bootstrap

The Bootstrap class loader loads the basic runtime classes provided by the JVM.

Extension

The Extension class loader loads classes from JAR files present in the system extensions directory, domain-dir/lib/ext (that is, libraries of type ext). It’s parent to the Public API class loader.

The Extension classloader no longer works using the Java Optional Package mechanism (see http://docs.oracle.com/javase/8/docs/technotes/guides/extensions/extensions.html) since this mechanism is no longer supported in Java 11+.
Instead, this classloader is designed to "trick" the server in handling delegation much sooner.

Public API

The Public API class loader makes available all classes specifically exported by the Payara Server runtime for use by deployed applications.

This includes, but is not limited to, Jakarta EE API, Eclipse MicroProfile and the Payara Platform Public API.

Parents the Common class loader.

Common

The Common class loader loads JAR files in the`as-install/lib` directory, followed by JAR files in the domain-dir/lib directory.

Using domain-dir/lib is recommended whenever possible, and required for custom login modules and security realms.

Parents the Connector class loader.

Connector

The Connector class loader is a single class loader instance that loads individually deployed connector modules, which are shared across all applications.

Parents both the Applib class loader and the LifeCycleModule class loader.

LifeCycleModule

The LifeCycleModule class loader is created once per lifecycle module. Each lifecycle module’s classpath is used to construct its own class loader.

For more information on lifecycle modules, see Developing Lifecycle Listeners.

Applib

The Applib class loader loads the library classes (specifically, libraries of the app type), specified during deployment, for a specific enabled module or Jakarta EE application;

One instance of this class loader is present in each class loader universe;

Parents the Archive class loader.

When multiple deployed applications use the same library, they share the same instance of the library. One library cannot reference classes from another library.

Archive

The Archive class loader loads classes from the WAR, EAR, and JAR files or directories (for directory deployment) of applications or modules deployed in Payara Server.

This class loader also loads any application-specific classes generated by the Payara Server runtime, such as stub classes or servlets generated by JSP pages.

Classloaders that are lower in the hierarchy will first delegate searching for a class to a classloader higher in the hierarchy.

If none of the classloaders higher in the hierarchy finds the class, the classloader will attempt to find the class itself.

Here, you can see that:

  • Classes provided by Payara Server have higher priority than classes provided by an application

  • Classes provided by Payara Server have higher priority than installed libraries of type common and app.

  • Classes in installed libraries have higher priority than classes provided by an application

  • To install a library with a higher priority than classes provided by Payara Server, it should be installed with the ext type.

Configuring Delegation

The Jakarta Servlet specification recommends that a web module’s class loader look in the local class loader before delegating to its parent.

You can make this class loader follow the delegation inversion model in the Servlet specification by setting delegate="false" in the class-loader element of the payara-web.xml file. It is safe to do this only for a web module that does not interact with any other modules.

For more details, see "class-loader" in the Payara Server Application Deployment section. An example of how to use this element is given in the disabling classloading delegation on web application section.

The default value is delegate="true", which causes a web module’s class loader to delegate in the same manner as the other class loaders. You must use delegate="true" for a web application that accesses EJB components or that acts as a web service client or endpoint.

For a number of packages, including java.* and jakarta.\*, symbol resolution is always delegated to the parent class loader regardless of the delegate setting. This prevents applications from overriding core Java runtime classes or changing the API versions of specifications that are part of the Jakarta EE platform.

The delegation hierarchy can also be tweaked using the enhanced classloading features. For example, it’s possible to give the classes provided by an application the highest priority (by disabling classloading delegation), or completely hide (isolate) classes provided by Payara Server from a deployed application.

Class Loader Universes

Access to components within applications and modules installed on the server occurs within the context of isolated class loader universes, each of which has its own Applib and Archive classloaders.

Application Universe

Each application has its own class loader universe, which loads the classes in all the modules in the application.

Individually Deployed Module Universe

Each individually deployed EJB JAR or web WAR has its own class loader universe, which loads the classes in the module.

A resource such as a file that is accessed by a Jakarta EE application component must be in one of the following locations:

  • A directory pointed to by the Libraries field or --libraries option used during deployment

  • A directory pointed to by the library-directory element in the application.xml deployment descriptor

  • A directory pointed to by the application or module’s classpath; for example, a web module’s classpath includes these directories:

    module-name/WEB-INF/classes
    module-name/WEB-INF/lib

Installing Libraries in a Domain

Since each application or individually deployed module class loader universe is isolated, an application or module cannot load classes from another application or module. This prevents two similarly named classes in different applications or modules from interfering with each other.

To circumvent this limitation for libraries, utility classes, or individually deployed modules accessed by more than one application, you can include the relevant path to the required classes by installing a library with those classes into the server domain. This is useful if you’d like to build an application for flexible deployments and configure it with classes dropped on the classpath, or if you’d like multiple deployed applications to share the same library.

If an internal server resource, such as a JDBC connection pool, requires an additional library, you can install it directly into the Payara Server domain too.

To install a library into a server domain, use the asadmin add-library command.

This command accepts the --type argument, which accepts the following options:

common

The library is installed as a common library into the lib directory in the Payara Server domain

ext

The library is installed as an "extension" library into the lib/ext directory in the Payara Server domain

app

the library is installed as an application library into the lib/applibs directory in the Payara Server domain

Common Libraries

Common libraries are available to all applications or modules deployed on servers with the same configuration. There are several levels of common libraries:

  • Shared by all applications deployed on the same Payara Server installation - located in the glassfish/lib directory in the Payara Server installation

  • Shared by all applications deployed in the same Payara Server domain - located in the lib directory in that Payara Server domain directory

  • Shared by all applications deployed on instances that share the same configuration - located in the config/<config-name>/lib directory in the particular Payara Server domain directory

Only libraries shared by applications in the same domain can be installed by the add-library asadmin command. All other types have to be installed manually by copying the libraries into the particular locations.

Extension Libraries

Application developers can use libraries installed as extension libraries to extend the functionality of the core Payara Server platform. For example, an Oracle Database JDBC driver should be installed as an extension library if it’s going to be used via JPA to use Oracle-specific JPA features.

Or a Java agent library should be installed as an extension library if the Java agent instruments classes in Payara Server to use classes from the agent library itself.

Classes in extension libraries will be available to all deployed applications. If you need that classes from an extension library are available also to Payara Server’s internal classes (and OSGi bundles in general) as is often the case with Java agents, you also need to add the packages exported by the library into OSGi boot delegation.

This is done by modifying the as-install/config/osgi.properties configuration file in the Payara Server installation and adding the packages to the list in the org.osgi.framework.bootdelegation property.

Packages exported by Oracle JDBC drivers are already added by default.

Extension libraries are added to the system classpath at the beginning of the classpath, so that they have higher priority than all other classes and libraries on the classpath. This is because the Java extension mechanism isn’t supported in Java 11 and newer and the official recommend way to replace it is to add the libraries to the classpath directly.

Since defining the java.ext.dirs on Java 11+ leads to an error, this JVM option cannot be used with Java 11+ and extension libraries are automatically added as classpath elements.

Application Specific Libraries

You can specify module or application-specific library classes in one of the following ways:

  • Use the Administration Console. Open the Applications component, then go to the page for the type of application or module. Select the Deploy button. Type the comma-separated paths in the Libraries field.

  • Use the asadmin deploy command with the --libraries option and specify comma-separated paths. For more details, see the Payara Server Reference Manual.

  • Use the asadmin add-library command with the --type app option. For details, see the add-library.

None of these alternatives apply to application clients. For more information, see Using Libraries with Application Clients.

You can update a library JAR file using dynamic reloading or by restarting (disabling and re-enabling) a module or application. To add or remove library JAR files, you can redeploy the module or application. Application libraries are included in the Applib class loader. Paths to libraries can be relative or absolute.

A relative path is relative to domain-dir/lib/applibs. If the path is absolute, the path must be accessible to the domain administration server (DAS). Payara Server automatically synchronizes these libraries to all remote instances when a cluster or deployment group is restarted. However, libraries specified by absolute paths are not guaranteed to be synchronized.

You can also use application-specific class loading to access different versions of a library from different applications.

If multiple applications or modules refer to the same libraries, classes in those libraries are automatically shared. This can reduce the memory footprint and allow sharing of static information. However, applications or modules using application-specific libraries are not portable.

If you see an access control error message when you try to use a library, you may need to grant permission to the library in the server.policy file. For more information, see Changing Permissions for an Application.

Packaging the Client JAR for One Application in Another Application

By packaging the client JAR for one application in a second application, you allow a Jakarta EE component in the second application to call an EJB component in the first (dependent) application, without making either of them accessible to any other application or module.

As an alternative for a production environment, you can have the Common class loader load the client JAR of the dependent application as described in the previous section.

To do this follow these steps:

  1. Deploy the dependent application.

  2. Add the dependent application’s client JAR file to the calling application.

    • For a calling EJB component, add the client JAR file at the same level as the EJB component. Then add a Class-Path entry to the MANIFEST.MF file of the calling EJB component.

    • For a calling web component, add the client JAR file under the WEB-INF/lib directory.

      If you need to package the client JAR with both the EJB and web components, set delegate="true" attribute in the class-loader element of the payara-web.xml file.

      This changes the Web class loader so that it follows the standard class loader delegation model and delegates to its parent before attempting to load a class itself.

      For most applications, packaging the client JAR file with the calling EJB component is sufficient. You do not need to package the client JAR file with both the EJB and web components unless the web component is directly calling the EJB component in the dependent application.
  3. Deploy the "client" application. The calling EJB or web component must specify in its glassfish-ejb-jar.xml or payara-web.xml file the JNDI name of the EJB component in the dependent application. Using an ejb-link mapping does not work when the EJB component being called resides in another application.

Enhanced Classloading

This sections below cover the enhanced class loading functionality provided by the Payara Platform.

Default Class and Library Loading

Payara Server has included many standard Java libraries and packages, for example Jackson, Nimbus JOSE, Logback, and others to use. These libraries are located on the as-install/modules directory.

The default class loading mechanism of Payara Server works like this: When loading classes that belong to a library or framework that is included in the server, the server will always load those classes even if the application itself includes different versions.

In some cases, application developers will want to include a different version of the libraries that are already included on the server. Common use cases for this are:

  1. Use a newer version of a library that is included in the server. For example, Payara Server includes the Jackson library, and you might need to use a newer version that includes a specific feature you want to use.

  2. Use an older version of a library included within the server in order to support legacy applications. For example, you are using an older version of Icefaces that depends on an older version of Jakarta Faces.

Unfortunately, due to the way the default class loading hierarchy works, this will not be possible, and all libraries included with the server libraries will take precedence.

Disable Classloading delegation

As detailed in Configuring Delegation, it is possible to invert/disable the way that delegation works as per the requirements of the Jakarta Servlet specification. The Payara Platform introducers greater delegation disabling mechanisms, detailed in the following sections.

Disable Classloading delegation globally

To disable class loading delegation globally, you can set the system property fish.payara.classloading.delegate to false.

Disable Classloading delegation locally

It’s possible to disable class loading delegation directly at the application level. This can be done for both WAR and EAR applications.

For Web applications, you can include <class-loader delegate="false"/> element in the payara-web.xml/glassfish-web.xml deployment descriptors.

Here’s an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <class-loader delegate="false"/>
</glassfish-web-app>

For EAR applications, you can include the <classloading-delegate>false</classloading-delegate> element in the glassfish-application.xml deployment descriptor.

Here is an example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-application PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Java EE Application 6.0//EN" "http://glassfish.org/dtds/glassfish-application_6_0-1.dtd">
<glassfish-application>
    <classloading-delegate>false</classloading-delegate>
</glassfish-application>

Extreme Classloading Isolation

It’s possible to configure an extreme isolation level on the class loading delegation for deployed applications. With this extreme isolation behavior, a deployed application can force the server to load only classes and resources from libraries included on the server that belong to whitelisted packages defined on its deployment descriptors.

To configure whitelist packaging you can use the <whitelist-package> element on the payara-web.xml / glassfish-web.xml (for WAR artifacts) or the glassfish-application.xml (for EAR artifacts) deployment descriptors. This element can be included multiple times to whitelist multiple packages.

Here is an example of whitelisting both the Google Guava, Jackson and Faces Config packages for a WAR application:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <whitelist-package>com.google.guava</whitelist-package>
  <whitelist-package>com.fasterxml.jackson</whitelist-package>
  <whitelist-package>com.sun.faces.spi.FacesConfigResourceProvider</whitelist-package>
</glassfish-web-app>

The whitelist syntax is simple: Define the name of the package which contains the classes or resources in question. For example writing com.google would whitelist all Google libraries included on the server, while writing com.google.guava would only whitelist the Google Guava library instead.

To enable this extreme isolation behavior, at least one whitelist-package element must be defined in the appropriate descriptor.

Default Whitelisted Classes

Certain classes are whitelisted automatically, meaning they will always be loaded from the server libraries and follow the default classloading hierarchy, even if this feature is turned on.

This is because these packages are required by the server and therefore cannot be loaded from application modules:

  • java

  • javax

  • com.sun

  • org.glassfish

  • org.apache.jasper

  • fish.payara

  • com.ibm.jbatch

  • org.hibernate.validator

  • org.jboss.weld

  • com.ctc.wstx

Likewise, the default whitelisted resources are:

  • META-INF/services/jakarta.

  • META-INF/services/org.glassfish.

  • META-INF/services/java.