Prevent Classloading-Related Issues with Payara BOM

Photo of Patrik Duditš by Patrik Duditš

The runtime image of Payara Server consists of over 400 modules. Half of these do not come directly from the Payara codebase, but are various third-party APIs, their implementations and helper libraries. How do you choose the correct versions of your application's libraries so they are not in conflict with the ones in the server runtime?

Version mismatch usually manifests itself with various classloading-related exceptions during application startup or runtime. Usually those are ClassNotFoundExceptions NoClassDefFoundErrors or, more often, NoSuchMethodErrors.

Since Payara Platform 5.194 we are publishing the Bill of Material, shortly referred to as BOM, which lists versions of all relevant third-party dependencies of Payara Server and Payara Micro. It is a Maven POM artifact containing managed dependencies to be used in import scope in Maven. Gradle users use keyword platform to take advantage of versions defined in the BOM. Maven coordinates of the BOM are fish.payara.api:payara-bom.

Using the BOM

Payara forks some of the third party content so that fixes that are vital for us are available in time for our release. In addition to declaring the dependency, one also needs to use our Patched_Projects repository in order to be able to fetch all dependencies in versions corresponding to target Payara Platform version.

Definition of an web application that can utilize all of Jakarta EE and MicroProfile APIs available in Payara Server would therefore look like this:

 
 

A more complete example can be seen in our GitHub repository Payara-Examples.

Contents of the BOM

All relevant dependencies defined in Bill of Material artifact are listed in Payara Server Documentation. The dependencies could be put in these several categories:

  • Payara Server and Micro Distributions
  • Payara Vendor-Specific APIs
  • Payara Arquillian containers
  • Jakarta EE APIs
  • Microprofile APIs
  • OSGi APIs available in Server
  • Implementations and utility modules used in the products, chiefly
    • Jersey
    • EclipseLink
    • Jackson
    • Hazelcast
    • Yasson
    • Tyrus

Picking the Right Scope

The best practice regarding BOMs is to not enforce the scopes of dependencies. We broke this principle only in few cases: Jakarta and MicroProfile APIs prescribe dependency scope provided, as those are surely present in the target platform. We also default scope of our Arquillian containers to test scope, as one would very seldom should use it in other scope.

So it is up to you, the user, to pick the right scope. General rule of thumb would be, that if you want to use an artifact present in subdirectory glassfish/modules of Payara installation, you should use scope provided. If you're using Payara Micro, look into its root directory and its subdirectory runtime.

Help, BOM Didn't Solve my Dependency Issue!

So, what to do, when you no longer see any discrepancy between you application's WEB-INF/lib folder and server's glassfish/modules? Nothing present in modules directory is present in WEB-INF/lib and any related artifacts have versions matching server's?

The answer might lie higher in classloader hierarchy:

  • Is there OSGi application deployed that might contain the artifact's classes?
  • Is artifact included in any of deployed resource adapter applications?
  • Is artifact present in domain's lib/ directory, or lib/ext/ directory?

The ultimate diagnostic for figuring out these problems is setting a breakpoint in debugger at the location of error (or setting Exception breakpoint) and evaluating:

getClass().getClassLoader().getResource(
  getClass().getName().replace('.','/')+".class")

Resulting URL will give you a hint on where is the offending class located, and that might give you a hint why it cannot find what's it looking for. Especially those in lib/ cannot access those in server modules.

If you cannot use the version provided with Payara, you can instruct the server not to use its resources by utilizing non-delagating classloader or classloader isolation.

But hopefully, utilizing the BOM in your project will be all you need to keep your dependencies aligned with the version of Payara Server you're deploying to.

Comments