Resolving Mockito Errors After JDK Upgrades in Liferay Portal

By Rafał Pydyniak | 2025-04-30

As everyone knows upgrading Liferay Portal or migrating to a newer JDK version (such as JDK 21) can be a pain. Developers might encounter unexpected errors that can slow down development and testing processes. In this article, we'll explore a specific issue related to Mockito and provide a simple solution.

The Problem: Mockito Errors After JDK Upgrade

If you've recently upgraded your Liferay environment to use JDK 21 (or possibly JDK11 or JDK17), you might encounter test failures with error messages similar to:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field static final java.lang.invoke.MethodHandles$Lookup 
java.lang.invoke.MethodHandles$Lookup.IMPL_LOOKUP accessible: module java.base does not "opens java.lang.invoke" to unnamed module

These errors occur because newer JDK versions have implemented a stronger module system (Project Jigsaw) that restricts access to internal JDK packages. Mockito relies on accessing these internal classes for its functionality.

Understanding the Root Cause

The Java Platform Module System (JPMS) introduced in Java 9 enforces stricter encapsulation of internal Java APIs. Libraries like Mockito that use reflection to access internal JDK classes need explicit permission to do so in the form of --add-opens directives.

In our specific case, Mockito needs access to:

  • java.lang package from the java.base module
  • java.lang.invoke package from the java.base module

The Solution: Adding JVM Arguments

To resolve this issue and allow your tests to run properly after upgrading to JDK 21, you need to add specific JVM arguments to your Gradle build configuration. Here's how to do it:

For Gradle-based Liferay Projects

Add the following to your build.gradle file in the test configuration section:

test {
    jvmArgs = ['--add-opens', 'java.base/java.lang=ALL-UNNAMED',
               '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED']
}

For multi modules project you will need to add it to every module that uses Mockito.

My advice? Add this to all subprojects using top level build.gradle:

subprojects { subproject ->
    test {
        jvmArgs = ['--add-opens', 'java.base/java.lang=ALL-UNNAMED',
                   '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED']
    }
}

This way you won't have to remember about that each time you use Mockito.

For Maven-based Liferay Projects

If you're using Maven instead of Gradle, these arguments in your pom.xml should do the trick:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.2</version>
    <configuration>
        <argLine>
            --add-opens java.base/java.lang=ALL-UNNAMED
            --add-opens java.base/java.lang.invoke=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

How These Arguments Work

Let's understand what these arguments do:

  • --add-opens java.base/java.lang=ALL-UNNAMED: This opens the java.lang package from the java.base module to allow access from unnamed modules (which includes your application and its dependencies like Mockito).

  • --add-opens java.base/java.lang.invoke=ALL-UNNAMED: Similarly, this opens the java.lang.invoke package to unnamed modules.

These arguments effectively tell the JVM to relax its module encapsulation rules specifically for these packages, allowing Mockito to function correctly through reflection.

Is it new issue?

Well not really. I would say now it happens to many of us as Liferay has dropped support for JDK8 some time ago. Actually this is what happened to us when I first faced the issue: I was migrating the project to newest Liferay version and we were forced to update JDK as well. Earlier we did not want to do that due to other limitations we had and extra effort needed to resolve them.

Also just a month earlier someone I met on DevCon asked me on Slack about exactly the same specific error. This is why I thought I will create this as an article even though it is rather simpler article than the ones I normally try to publish.

Additional Considerations

Besides these "specific" error fixes you should of course also remember about updating your Mockito version to the newest one. Along with other libraries like Lombok which can also lead to unexpected tests errors for example with @Slf4j (which also happened to me updating Lombok did the trick so I'm not going into more details)

Conclusion

Upgrading to newer Liferay or JDK can bring numerous benefits but it almost always comes with some effort to make everything work. Nevertheless updates are important and should be done regularly which also simplifies each of them. Hopefully the solution above can help you at least a little bit to resolve Mockito related errors in your Liferay Portal projects after such upgrades.


Do you have any questions or doubts? Feel free to contact me directly.

Looking for expert Liferay development services? Contact InnRay for a consultation.

Copyright: Rafał Pydyniak