Search code examples
javaspringjunitmockitopowermock

Migration from Java 8 to Java 17 And Spring 6 JUnit4 failing due to version mismatch


I'm migrating an enterprise product. The things I have migrated are as follows:

  • JDK 1.8 to JDK 17

  • Spring 5.2.2.RELEASE to Spring 6.0.0

Now, in the process of migration, some tests have started to fail.

I have the below dependencies which are in older versions. I have tried to upgrade the versions but it's somehow not working.

Can someone please advise on which version needs to be there to resolve the test cases failures?

pom.xml:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.6</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.6.6</version>
    <scope>test</scope>
</dependency>

Test Failure Log:

ClassATest.initializationError » Objenesis java.lang...
ClassBTest.initializationError » Objenesis java.lang.refl...

Running com.util.SupportMonitoringUtilTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! - in com.util.SupportMonitoringUtilTest
initializationError(com.util.SupportMonitoringUtilTest)  Time elapsed: 0 sec  <<< ERROR!
org.objenesis.ObjenesisException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.reflect.InvocationTargetException
Caused by: java.lang.IllegalAccessError: class jdk.internal.reflect.ConstructorAccessorImpl loaded by org.powermock.core.classloader.MockClassLoader @752573df cannot access jdk/internal/reflect superclass jdk.internal.reflect.MagicAccessorImpl

Solution

  • You need to upgrade/add the following dependencies for PowerMock & Mockito to support JDK 17:

    • Newer version of powermock-module-junit4 needs to be added. Update powermock-module-junit4 from 1.6.6 to 2.0.9 (which is the latest version at the time of writing the answer).
    • Newer version of powermock-api-mockito needs to be added. Update powermock-api-mockito (1.6.6) to powermock-api-mockito2 (2.0.9) (which is the latest version at the time of writing the answer).
    • Newer version of javassist needs to be added. Update javassist version to the latest version (3.29.2-GA) (at the time of writing the answer).

    Note: You might face this error while running the tests on JDK 17:

    Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not "opens java.lang" to unnamed module
    

    To avoid this, you will need to tell maven by adding this --add-opens java.base/java.lang=ALL-UNNAMED via maven-surefire-plugin when running this.

    Another point to be noted: You don't need to add Mockito dependency separately. powermock-api-mockito2 comes with the mockito-core dependency.

    pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>demo-2</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>demo-2</name>
        <description>Sample</description>
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
        </properties>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-api-mockito2</artifactId>
                <version>2.0.9</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.powermock</groupId>
                <artifactId>powermock-module-junit4</artifactId>
                <version>2.0.9</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.29.2-GA</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.1.2</version>
                    <configuration>
                        <argLine>
                            --add-opens java.base/java.lang=ALL-UNNAMED
                        </argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    This should work. I have tested on my local, it's working.

    Sample codebase example for testing here.