netty «jdk.internal.misc.Unsafe»

Logo de Java

Cuando pasamos de java 8 a una versión más moderna, java 11 por ejemplo, puede que programas o librerías que nos funcionaban empiecen a darnos excepciones del estilo

java.lang.IllegalAccessException: class io.netty.util.internal.PlatformDependent0$6 cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @84b8f0f

En este caso, ha sido la librería netty, muy utilizada para comunicaciones entre ejecutables java por muchos frameworks.

El error se debe al uso de la clase jdk.internal.misc.Unsafe de Java. Esta clase permite manipular a bajo nivel la memoria, las clases, los objetos, etc. Y es una clase cuya utilización no es segura, puesto que es fácil comenter errores con ellas, tener efectos inesperados, etc.

Sin embargo, su potencia hace que se use en muchos de los frameworks más modernos. Por ejemplo, manipulando directamente memoria podemos conseguir mayor velocidad de proceso que utilizado los métodos normales de java.

¿Y a qué se debe el error?. El error se debe a que en java 8 esta clase podía utilizarse sin ningún problema. Pero en versiones poseteriores se ha metido en un módulo separado que no es accesible de forma estándar. De hecho, en java 8, la clase era sun.misc.Unsafe. En java 11 se han separado los métodos en dos clases y se han metido en dos módulos distintos. jdk.internal.misc.Unsafe en java.base y sun.misc.Unsafe en jdk.unsupported.

Si queremos seguir pudiendo usarlos o que las librerías que usemos, como netty, no protesten, debemos dar acceso a nuestro programa a dichos módulos. Una forma de hacerlo es añadir las siguientes opciones en nuestro comando java de arranque de nuestro ejecutable.

–add-opens java.base/jdk.internal.misc=ALL-UNNAMED

–add-opens indica que debemos abrir un módulo y qué paquete dentro de ese módulo. Podríamos poner –add-exports también. La diferencia entre ambos es que el segundo abre los módulos permitiendo usar sólo sus clases y métodos públicos. Mientras que el primero lo abre totalmente permitiendo, por reflexión, acceder también a métodos y atributos privados.

Luego van el nombre del módulo que queremos abrir y el paquete dentro de ese módulo. Y finalmente, tras el igual, a qué módulo se lo queremos abrir. Por compatibilidad con java 8 y anteriores, que no existían módulos, está la opción ALL-UNNAMED. Esta opción da acceso a esos módulos a todas las clases java que no están en ningún módulo.

En nuestro ejemplo, nos bastaría con abrir solo este módulo/paquete java.base/jdk.internal.misc, ya que la excepción sólo protesta de no tener acceso a la clase Unsafe de este paquete.

Para el caso concreto de netty, tenemos una opción más específica

-Dio.netty.tryReflectionSetAccessible=true

Esta entrada ha sido publicada en java, Lenguajes de Programación y etiquetada como , , , . Guarda el enlace permanente.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.