¿Cómo ocultar el aviso de "acceso reflectivo ilegal" en java 9 sin el argumento JVM?
netty java-9 (4)
Hay formas de desactivar la advertencia de acceso ilegal, aunque no recomiendo hacerlo.
1. enfoque simple
Dado que la advertencia se imprime en la secuencia de error predeterminada, simplemente puede cerrar esta secuencia y redirigir stderr
a stdout
.
public static void disableWarning() {
System.err.close();
System.setErr(System.out);
}
Notas:
- Este enfoque combina errores y flujos de salida. Eso puede no ser deseable en algunos casos.
- No puede redirigir el mensaje de advertencia simplemente llamando a
System.setErr
, ya que la referencia a la secuencia de error se guarda en el campoIllegalAccessLogger.warningStream
principio de la JVM bootstrap.
2. Acercamiento complicado sin cambiar stderr.
Una buena noticia es que se puede acceder a sun.misc.Unsafe
en JDK 9 sin advertencias. La solución es restablecer el IllegalAccessLogger
interno con la ayuda de API no IllegalAccessLogger
.
public static void disableWarning() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe u = (Unsafe) theUnsafe.get(null);
Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
} catch (Exception e) {
// ignore
}
}
Intenté ejecutar mi servidor con Java 9 y obtuve la siguiente advertencia:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by io.netty.util.internal.ReflectionUtil (file:/home/azureuser/server-0.28.0-SNAPSHOT.jar) to constructor java.nio.DirectByteBuffer(long,int)
WARNING: Please consider reporting this to the maintainers of io.netty.util.internal.ReflectionUtil
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
Me gustaría ocultar esta advertencia sin agregar --illegal-access=deny
a las opciones de JVM durante el inicio. Algo como:
System.setProperty("illegal-access", "deny");
¿Hay alguna forma de hacer eso?
Todas las respuestas relacionadas que sugieren utilizar las opciones de JVM, me gustaría desactivar esto desde el código. ¿Es eso posible?
Para aclarar, mi pregunta es acerca de convertir esta advertencia del código y no a través de argumentos / indicadores de JVM como se indica en preguntas similares.
Hay otra opción que no viene con ninguna necesidad de supresión de flujo y que no se basa en API no documentadas o no compatibles. Al usar un agente Java, es posible redefinir módulos para exportar / abrir los paquetes requeridos. El código para esto sería algo así:
void exportAndOpen(Instrumentation instrumentation) {
Set<Module> unnamed =
Collections.singleton(ClassLoader.getSystemClassLoader().getUnnamedModule());
ModuleLayer.boot().modules().forEach(module -> instrumentation.redefineModule(
module,
unnamed,
module.getPackages().stream().collect(Collectors.toMap(
Function.identity(),
pkg -> unnamed
)),
module.getPackages().stream().collect(Collectors.toMap(
Function.identity(),
pkg -> unnamed
)),
Collections.emptySet(),
Collections.emptyMap()
));
}
Ahora puede ejecutar cualquier acceso ilegal sin aviso, ya que su aplicación está contenida en el módulo sin nombre, como por ejemplo:
Method method = ClassLoader.class.getDeclaredMethod("defineClass",
byte[].class, int.class, int.class);
method.setAccessible(true);
Para obtener la instancia de Instrumentation
, puede escribir un agente Java que sea bastante simple y especificarlo en la línea de comandos (en lugar de la ruta de -javaagent:myjar.jar
) usando -javaagent:myjar.jar
. El agente solo contendría un método de premain
como sigue:
public class MyAgent {
public static void main(String arg, Instrumentation inst) {
exportAndOpen(inst);
}
}
Alternativamente, puede adjuntar dinámicamente usando la API adjunta a la que se puede acceder de manera conveniente mediante el proyecto byte-buddy-agent (que yo escribí):
exportAndOpen(ByteBuddyAgent.install());
a la que deberías llamar antes del acceso ilegal. Tenga en cuenta que esto solo está disponible en JDK y en Linux VM, mientras que tendría que proporcionar el agente de Byte Buddy en la línea de comandos como agente de Java si lo necesitara en otras máquinas virtuales. Esto puede ser conveniente cuando desea que los archivos adjuntos automáticos en las máquinas de prueba y desarrollo donde normalmente se instalan los JDK.
Como han señalado otros, esto solo debería servir como una solución intermedia, pero entiendo perfectamente que el comportamiento actual a menudo rompe los rastreadores de registro y las aplicaciones de consola, por eso lo he utilizado en entornos de producción como una solución a corto plazo para usar Java 9 y Tanto tiempo que no encontré ningún problema.
Lo bueno, sin embargo, es que esta solución es robusta para futuras actualizaciones como cualquier operación, incluso el adjunto dinámico es legal. Usando un proceso de ayuda, Byte Buddy incluso trabaja en torno al auto-apego normalmente prohibido.
No conozco ninguna manera de lograr lo que estás pidiendo. Como ha señalado, deberá agregar opciones de línea de comandos ( --add-opens
, sin embargo, no --illegal-access=deny
) al lanzamiento de la JVM.
Tu escribiste:
Mi objetivo es evitar las instrucciones adicionales para los usuarios finales. Tenemos muchos usuarios con nuestros servidores instalados y eso sería un gran inconveniente para ellos.
A primera vista, sus requisitos solo dejan la conclusión de que el proyecto no está listo para Java 9. Honestamente, debe informar a sus usuarios que se necesita un poco más de tiempo para ser totalmente compatible con Java 9. Eso está totalmente bien, tan temprano después del lanzamiento.
Puede open
paquetes en module-info.java
o crear un open module
.
Por ejemplo: paso a paso los pasos 5 y 6 de la migración de su proyecto a Jigsaw
module shedlock.example {
requires spring.context;
requires spring.jdbc;
requires slf4j.api;
requires shedlock.core;
requires shedlock.spring;
requires HikariCP;
requires shedlock.provider.jdbc.template;
requires java.sql;
opens net.javacrumbs.shedlockexample to spring.core, spring.beans, spring.context;
}
open module shedlock.example {
requires spring.context;
requires spring.jdbc;
requires slf4j.api;
requires shedlock.core;
requires shedlock.spring;
requires HikariCP;
requires shedlock.provider.jdbc.template;
requires java.sql;
}