Skip to content
Advertisement

Unable to make field final transient java.lang.Class java.util.EnumSet.elementType accessible: module java.base does not “opens java.util” to unnamed

I get this error when I run this test using JDK 17:

java.lang.reflect.InaccessibleObjectException: Unable to make field final transient java.lang.Class java.util.EnumSet.elementType accessible: module java.base does not "opens java.util" to unnamed module @60addb54
    @Test
    public void testThatDeepCopyCopiesEmptySet() {
        SetOfEnumUserType setOfEnumUserType = createSetOfEnumUserType();
        EnumSet<PaymentMethodType> src = EnumSet.noneOf(PaymentMethodType.class);
        EnumSet<?> dest = (EnumSet<?>) setOfEnumUserType.deepCopy(src);
        assertThat(dest, (is(src)));
        assertThat(dest, not(isSameInstanceAs(src)));
        Class<?> srcType = (Class<?>) ReflectionTestUtils.getField(src, "elementType");
        Class<?> destType = (Class<?>) ReflectionTestUtils.getField(dest, "elementType");
        assertThat(srcType, (is(destType)));
    }

I tried adding this to my pom.xml based on other answers:

           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <compilerArgs>
                        <arg>--add-opens java.base/java.lang=ALL-UNNAMED</arg>
                        <arg>--add-opens java.base/java.util=ALL-UNNAMED</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire.plugin.version}</version>
                <configuration>
                    <argLine>--add-opens java.base/java.lang=ALL-UNNAMED</argLine>
                    <argLine>--add-opens java.base/java.util=ALL-UNNAMED</argLine>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <inherited />
                    </execution>
                </executions>
            </plugin>

But when I build, I now get this error:

Fatal error compiling: error: invalid flag: --add-opens java.base/java.lang=ALL-UNNAMED

Advertisement

Answer

@Holger is right, you should not hack into JDK internals. He also explained correctly that --add-opens is not a valid Maven Compiler option. Because he did not write an answer but comments instead, I am writing one. The credit is his.

As for the irritating comments about source and target versions 1.8, this is of course not the root cause of your problem. It is perfectly legal to compile under JDK 17 with compliance level 1.8.

Here is an MCVE – you should have provided one in the first place instead of an uncompilable code snippet and an incomplete POM:

Maven POM:

Please note:

  • --add-opens is now only in the Surefire configuration where it belongs, no longer in the compiler configuration.
  • I removed the illegal option <inherited /> from the configuration.
  • I am relying on the default Surefire execution instead of specifying another one. In your use case that might not be what you want, but for the MCVE it is the simplest option.
  • Instead of two <argLine> tags only one of which will be picked up by Surefire, you have to specify both --add-opens options within the same tag. You can conveniently separate them by newlines.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>SO_Java_AddOpens_69753263</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <surefire.plugin.version>2.22.2</surefire.plugin.version>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire.plugin.version}</version>
        <configuration>
          <argLine>
            --add-opens java.base/java.lang=ALL-UNNAMED
            --add-opens java.base/java.util=ALL-UNNAMED
          </argLine>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>

Test code and helper enum:

package org.example;

public enum PaymentMethodType {
  FOO, BAR, ZOT
}

I simplified your test case as follows:

package org.example;

import org.junit.Test;

import java.lang.reflect.Field;
import java.util.EnumSet;

import static org.junit.Assert.assertEquals;

public class MyTest {
  @Test
  public void testThatDeepCopyCopiesEmptySet() throws NoSuchFieldException, IllegalAccessException {
    EnumSet<PaymentMethodType> src = EnumSet.noneOf(PaymentMethodType.class);
    Field elementType = EnumSet.class.getDeclaredField("elementType");
    elementType.setAccessible(true);
    Class<?> srcType = (Class<?>) elementType.get(src);
    assertEquals(PaymentMethodType.class, srcType);
  }
}
Advertisement