Archivo de la etiqueta: Java

Multi-Release JARs

En los últimos años Java ha estado evolucionando muy rápido con el nuevo ciclo de distribución en el que se liberan 2 nuevas versiones por año.

Con la nueva versión 17 Long Time Support (LTS) de la JDK y la versión 18 a la vuelta de la esquina, muchos desarrollos aún están asimilando la anterior versión LTS, la JDK 11.

Se hace patente el hecho que los desarrollos de aplicaciones Java no pueden seguir el ritmo en el que van apareciendo las nuevas características del lenguaje y por eso muchas de ellas tardan en ser de uso general. Una de las consecuencias de este hecho es que los desarrolladores de librerías y frameworks están forzados a esperar hasta que la base de aplicaciones a los que dan soporte se adapta para seguir siendo compatibles con ellas.

Desde la aparición de Java 9 han aparecido mecanismos para paliar este hecho, posibilitando la construcción de artefactos compatibles con múltiples versiones de JDK: Uno de ellos son los Multi-Release JARs (MRJAR), que hace posible integrar en un mismo componente (fichero JAR) diversas versiones de código compatibles con múltiples versiones de JDK.

En este artículo se explica el funcionamiento de los MRJAR así como su integración en un proyecto construido mediante Maven.

Seguir leyendo Multi-Release JARs

Incidencias de class loader

En el lenguaje de programación Java, para identificar una clase especifica se tienen en cuenta principalmente 2 cosas: El nombre del package en el que se encuentra y el propio nombre de la clase. Mediante estos 2 valores, el sistema de class loaders de la máquina virtual identifica y carga la diferentes clases según sean necesarias durante la ejecución de una aplicación. Este mecanismo tiene un problema bastante conocido cuando más de una clase con el mismo nombre y package se encuentran contenidas en ficheros jar o directorios diferentes. Este fenómeno es una de las variantes del denominado Jar Hell que en este caso concreto consiste en que no todas las clases pertenecientes al mismo package que son cargadas por el sistema de class loaders proceden de la misma ubicación (directorio de clases o fichero jar), lo que puede ocasionar incompatibilidades o errores inesperados si estas no pertenecen a la misma versión de código.

La especificación de Java define un mecanismo denominado package sealing que puede aplicarse opcionalmente para garantizar que todas las clases pertenecientes a un mismo package son cargadas desde el mismo fichero jar. En caso de que la máquina virtual en un momento determinado intente cargar una clase de un package definido como sellado y esta pertenezca a un fichero jar distinto al del resto de clases del mismo package ya cargadas, se producirá un error advirtiendo de ello. Desafortunadamente, no todas las librerías hacen uso de este mecanismo, por lo que a veces es complicado ver si esta puede ser la causa de un error determinado.

En este artículo se exponen diferentes casuísticas derivadas de este fenómeno y de como identificar la causa de un error de este tipo para poder solucionarlo.

Seguir leyendo Incidencias de class loader

Java Platform Debug Architecture

La Java Platform Debug Architecture o JPDA es la arquitectura que implementa los mecanismos de debug dentro de la JVM. Se trata de una arquitectura multicapa formada por varios componentes:

  • Java Debug Interface (JDI): Define la interfaz necesaria para implementar debuggers que se conectarán a la JVM a fin de enviar las diferentes ordenes que se produzcan durante la sesión de debug. Las funcionalidades de debug de los diferentes IDE son ejemplos de front-end que implementan esta interfaz.
  • Java VM Tooling Interface (JVM TI): Define los servicios que permiten instrumentalizar la JVM. Esto va desde la monitorización, la manipulación de código en caliente, la gestión de threads de ejecución, el debug de código y otras muchas funciones más. Todo ello se consigue mediante el uso de los denominados agents nativos que es especifican durante el arranque de la JVM mediante el flag -agentlib:<nombre librería>. En el caso concreto del debug, se utiliza el JWPD agent para procesar las peticiones que se envían desde el front-end del debugger. Los servicios implementados por el JWPD agent en esta capa forman el back-end del debugger que se conecta directamente con el proceso en ejecución de la JVM que está siendo debugado.
  • Java Debug Protocol (JDWP): Define el protocolo de comunicación entre los procesos front-end y el back-end del debugger a través de varios canales de comunicación que incluyen socket y memoria compartida.

En este artículo se muestra una visión práctica de como configurar la conexión a la JVM para poder las depurar aplicaciones que se ejecuten sobre ella.

Seguir leyendo Java Platform Debug Architecture

NoClassDefFoundError en la inicialización de una clase Java

Los bloques de código estático en el lenguaje de programación Java són un mecanismo de inicialización de los recursos estáticos de una clase
que se ejecuta en el momento en que se interactua con dicha clase por primera vez. Un fallo producido dentro de dichos bloques estáticos puede provocar
errores inesperados en la ejecución del programa. En este post se habla de una de la posibles consecuencias de un error de este tipo y de cómo puede
ser identificado.

Seguir leyendo NoClassDefFoundError en la inicialización de una clase Java

Spring Boot – Configuración del contenedor subyacente

Una de las principales características del framework Spring Boot es permite la ejecución de aplicaciones web sin necesidad de usar servidores de aplicaciones externos donde desplegarlas. Esto lo consigue mediante el uso de un contenedor incrustado en la misma aplicación (Tomcat, Jetty Undertow). Aunque el framework configura por defecto este contenedor con valores válidos en muchos de los casos, a veces las peculiaridades de las aplicaciones hacen que se tengan que modificar ciertos parámetros de la configuración, como por ejemplo el soporte para HTTPS o el tamaño máximo peticiones de las peticiones, por poner algunos ejemplos. En este post se explicará la manera de personalizar estos valores.

Seguir leyendo Spring Boot – Configuración del contenedor subyacente

ResourceBundle – Localización de recursos

La API estándar de Java provee de mecanismos para la localización de recursos (mensajes de texto, URLs a imágenes u otros recursos…) mediante la utilización de la clase ResourceBundleLa forma más conocida y habitual de usarlos es a través de ficheros de propiedades, en los que se especifican los recursos a utilizar para cada localización en forma de clave – valor, pero existen otras posibilidades, como por ejemplo la utilización de clases java.

Seguir leyendo ResourceBundle – Localización de recursos

Orden de ejecución de los métodos de un test case de JUnit4

Deprecated

Aunque quizá JUnit4 sea el framework de testing más extendido en el ecosistema Java, adolece de ciertas limitaciones «de fábrica» que según como se mire son difíciles de explicar. Una de ellas para mi gusto es la dificultad de poder marcar el orden de ejecución de los métodos de una clase de test de forma sencilla. Entiendo que mirándolo de una forma purista cada uno de los métodos de un test case debe ser independiente y su ejecución no se debería ver afectada por el resto, pero en determinados casos es de mucha ayuda poder marcar el orden de ejecución, como por ejemplo poder probar la conexión a una fuente de datos antes de obtener los datos.

En este articulo se pretende exponer diferentes alternativas para dar respuesta a este caso de uso.

Seguir leyendo Orden de ejecución de los métodos de un test case de JUnit4

Error NullPointerException al evaluar una expresión ternaria

Descripción de error

Se produce un error de tipo NullPointerException al evaluar una expresión ternaria donde se mezclan valores de tipo primitivo (int, long, double…) con sus correspondientes tipos Wrapper (Integer, Long, Double) si el valor de resultante de la expresión es null.

Cuando la expresión condicional evalua y se asigna un valor no nulo, en este caso el segundo operando de la expresión, la operación funciona correctamente:

long val1 = 1;
		
Long valor2 = val1==1 ? val1 : (Long)null;
System.out.println("VALOR2 is null -> " + (valor2 != null));

VALOR2 is null -> true

En cambio, cuando se evalúa la condición y el valor resultante es null, tercer operando en el ejemplo, aunque este último se trate como un tipo objeto, se produce un error:

long val1 = 2;

Long valor2 = val1==1 ? val1 : (Long)null;
System.out.println("VALOR2 is null -> " + (valor2 != null));

Exception in thread "main" java.lang.NullPointerException

Solución propuesta

El error se produce porque en las expresiones ternarias de este tipo, el compilador escoge como tipo de retorno el valor primitivo, en el caso de los ejemplos anteriores el tipo long en lugar del tipo wrapper Long. Por esta razón, aunque se especifique una conversión explicita al tipo adecuado cuando se utiliza un valor nulo, siempre se producirá un error si ese es el resultado de la operación ya que el tipo primitivo no admite este tipo de valores.

La solución simple a este error es trasformar en todos los casos el valor resultante a un tipo wrapper. En el ejemplo, el segundo miembro de la operación es transformado a Long mediante el método valueOf para que todos los operandos sean de este tipo, que si admite valores nulos. El compilador escogerá este tipo para el resultado de la operación ya que es el único presente en las 2 alternativas, tanto si se cumple la condición como si no.

long val1 = 2;
		
Long valor2 = val1==1 ? Long.valueOf(val1) : (Long)null;
System.out.println("VALOR2 is null -> " + (valor2 != null));

VALOR2 is null -> false

 

Referencias

Error al tratar un dato de tipo CLOB con Hibernate en una base de datos PostgreSQL

Descripción de error

Se produce un error al recuperar datos de tipo LOB de una entidad a través de la capa de persistencia basada en JPA Hibernate si la base de datos subyacente es PostgreSQLSe produce un error de tipo:

org.postgresql.util.PSQLException: Bad value for type long

La configuración de los campos de una entidad incialmente es la siguiente:

@Basic(fetch=FetchType.LAZY)
@Lob
protected String stringLargeValue;

Entorno

  • JDK: 1.6. Es posible que ocurra también en versiones posteriores (No probado)
  • Framework de persistencia: JPA con Hibernate 3.6. No se ha probado con la versión 4 ni posteriores.
  • Base de datos: PostgreSQL 9.2.4, Es posible que ocurra también en versiones posteriores (No probado)

Solución propuesta

Parece ser que hay una falta de entendimiento entre Hibernate 3.6 y el driver de PostgreSQL porque lo que uno entiende como dato (Hibernate) el otro lo entiende como el puntero de tipo long para acceder a este (PostgreSQL) por lo que al hacer la extracción de datos este intenta hacer una conversión y provoca el error. Una posible solución se basa en configurar la propiedad de tipo LOB de la entidad con la anotación @Type de la siguiente manera para indicarle a Hibernate como debe tratar el valor recuperado:

@Basic(fetch=FetchType.LAZY)
@Lob
@Type(type="org.hibernate.type.TextType")
protected String stringLargeValue;

Generar esquema XSD a través de las clases de dominio con JAXB

Una operación muy habitual cuando se trabaja con JAXB para generar XML a partir de clases de dominio mediante anotaciones de JAXB es la de generar el esquema XSD asociado a la estructura de datos de dicho XML. Este esquema puede ser utilizado posteriormente para volver a generar las clases de dominio a través de JAXB. Se trata de una operativa muy común cuando se trabaja con servicios web REST para exponer la estructura de los mensajes de respuesta desde el servidor a los clientes para que estos puedan interpretarla, por ejemplo. 

Una manera muy sencilla de generar esta definición XSD cuando ya se tienen modeladas las clases de dominio a partir de las que se creará el XML mediante JAXB es utilizando el método generateSchema del contexto JAXB al que se han especificado las clases de dominio que forman el mensaje XML.

Seguir leyendo Generar esquema XSD a través de las clases de dominio con JAXB