Java`非法访问操作`方法将被弃用?

kos*_*spi 4 java reflection java-11

在 JDK 9+ JVM 之后,如果您使用一些非法访问,例如setAccessible().

我的问题

  1. 以后setAccessible()会不会被封?
  2. 此功能的官方参考(如果将被弃用)在哪里?

我在任何地方都找不到参考,提前致谢。

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.hazelcast.internal.networking.nio.SelectorOptimizer (file:/var/folders/9w/wp9vfqmn2ql0mp3lgym0bxf40000gn/T/toy.war-spring-boot-libs-0024b388-730f-430b-b21b-1611bd2ad612/hazelcast-4.0.2.jar) to field sun.nio.ch.SelectorImpl.selectedKeys
WARNING: Please consider reporting this to the maintainers of com.hazelcast.internal.networking.nio.SelectorOptimizer
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Run Code Online (Sandbox Code Playgroud)

Sla*_*law 6

1. Is setAccessible() will be blocked in the future?

No, AccessibleObject#setAccessible(boolean) is not deprecated nor, as far as I'm aware, are there plans to deprecate it.

The warning you see is related to this method but not directly. The Java Platform Module System introduced in Java 9 added stronger encapsulation, both at compile-time and run-time (i.e. reflection). The run-time rules are documented by #setAccessible(boolean):

This method may be used by a caller in class C to enable access to a member of declaring class D if any of the following hold:

  • C and D are in the same module.
  • The member is public and D is public in a package that the module containing D exports to at least the module containing C.
  • The member is protected static, D is public in a package that the module containing D exports to at least the module containing C, and C is a subclass of D.
  • D is in a package that the module containing D opens to at least the module containing C. All packages in unnamed and open modules are open to all modules and so this method always succeeds when D is in an unnamed or open module.

This method cannot be used to enable access to private members, members with default (package) access, protected instance members, or protected constructors when the declaring class is in a different module to the caller and the package containing the declaring class is not open to the caller's module.

This is a breaking change from Java 8 when reflection had free rein to access anything it wanted (assuming no SecurityManager). A breaking change is a problem since Java prides itself on backwards compatibility. In order to provide libraries and frameworks enough time to migrate they relaxed this strong encapsulation for a specific scenario (see below).


2. Where is official reference(that will be deprecated in the future) for this feature?

The warning you see is related to the --illegal-access option, which is documented by the java tool specification:

When present at run time, --illegal-access= takes a keyword parameter to specify a mode of operation:

Note: This option will be removed in a future release.

  • permit: This mode opens each package in each module in the run-time image to code in all unnamed modules ( such as code on the class path), if that package existed in JDK 8 [emphasis added]. This enables both static access, (for example, by compiled bytecode, and deep reflective access) through the platform's various reflection APIs. The first reflective-access operation to any such package causes a warning to be issued. However, no warnings are issued after the first occurrence. This single warning describes how to enable further warnings. This mode is the default for the current JDK but will change in a future release [emphasis added].

  • warn: This mode is identical to permit except that a warning message is issued for each illegal reflective-access operation.

  • debug: This mode is identical to warn except that both a warning message and a stack trace are issued for each illegal reflective-access operation.

  • deny: This mode disables all illegal-access operations except for those enabled by other command-line options, such as --add-opens. This mode will become the default in a future release [emphasis added].

The default mode, --illegal-access=permit, is intended to make you aware of code on the class path that reflectively accesses any JDK-internal APIs at least once. To learn about all such accesses, you can use the warn or the debug modes. For each library or framework on the class path that requires illegal access, you have two options:

  • If the component's maintainers have already released a fixed version that no longer uses JDK-internal APIs then you can consider upgrading to that version.

  • If the component still needs to be fixed, then you can contact its maintainers and ask them to replace their use of JDK-internal APIs with the proper exported APIs.

If you must continue to use a component that requires illegal access, then you can eliminate the warning messages by using one or more --add-opens options to open only those internal packages to which access is required.

To verify that your application is ready for a future version of the JDK, run it with --illegal-access=deny along with any necessary --add-opens options. Any remaining illegal-access errors will most likely be due to static references from compiled code to JDK-internal APIs. You can identify those by running the jdeps tool with the --jdk-internals option. For performance reasons, the current JDK does not issue warnings for illegal static-access operations.

To summarize the emphasized parts:

  1. The default mode is permit.
    • This allows code in the unnamed module (i.e. class-path) to access members within modules in the run-time image (i.e. the JDK), even if those members are in non-exported/non-opened packages (so long as those packages existed in JDK 8).
  2. Eventually the default mode will be deny.
    • Any code that hasn't been properly migrated at this point will stop working. This is why you see the warning—they want you to fix the problem (either yourself, if your code, or by submitting a bug report, if third-party code).
  3. The --illegal-access option itself will eventually be removed entirely.

In what release these changes will occur... I have no idea. However, the --illegal-access option will probably be removed one or two releases after the default mode becomes deny.

Update (May 31, 2021)

JEP 396: Strongly Encapsulate JDK Internals by Default was delivered with Java 16 and makes the default mode deny. The --illegal-access option is still present.

JEP 403:强烈包封物JDK塔内目前针对Java的17.这将使得permitwarn以及debug模式无效,尝试使用它们将导致正在发出警告。但是,该--illegal-access选项将暂时保留(但计划在未来版本中删除)。

  • 不完全是,很好的是它兼具了两者的优点。如果 QnA 保持原样,标记重复有利于从长远来看摆脱 QnA。有一些条款向现有问题添加信息,并对问题进行进一步编辑,说明为什么它不重复等。因此,也有重新开放的机会,因此我建议保留它,除非长期采取某些行动倾向于删除整个 QnA 。 (2认同)