jre vs jre-headless

2019/05/21

Problema

Al ejecutar una aplicación java con GUI se obtiene una traza similar a la siguiente:

may 21, 2019 11:33:53 PM org.bardsoftware.impl.eclipsito.BootImpl$1 uncaughtException
ADVERTENCIA: [uncaughtException]java.awt.HeadlessException
java.awt.HeadlessException
at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:207)
at java.awt.Window.<init>(Window.java:535)
at java.awt.Frame.<init>(Frame.java:420)
at javax.swing.JFrame.<init>(JFrame.java:218)
at net.sourceforge.ganttproject.GanttSplash.<init>(GanttSplash.java:32)
at net.sourceforge.ganttproject.GanttProject$14.run(GanttProject.java:1008)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:706)
at java.awt.EventQueue$3.run(EventQueue.java:704)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:715)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:218)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:133)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:122)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:118)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:110)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

may 21, 2019 11:33:54 PM net.sourceforge.ganttproject.GPLogger log
INFORMACIÓN: Waiting until main window closes
java.awt.HeadlessException
at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:207)
at java.awt.Window.<init>(Window.java:535)
at java.awt.Frame.<init>(Frame.java:420)
at javax.swing.JFrame.<init>(JFrame.java:218)
at net.sourceforge.ganttproject.GanttProjectBase.<init>(GanttProjectBase.java:102)
at net.sourceforge.ganttproject.GanttProject.<init>(GanttProject.java:191)
at net.sourceforge.ganttproject.GanttProject$15.run(GanttProject.java:1021)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:706)
at java.awt.EventQueue$3.run(EventQueue.java:704)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:715)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:218)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:133)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:122)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:118)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:110)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
may 21, 2019 11:33:54 PM org.bardsoftware.impl.eclipsito.BootImpl$1 uncaughtException
ADVERTENCIA: [uncaughtException]java.lang.NullPointerException
java.lang.NullPointerException
at net.sourceforge.ganttproject.GanttProject$15.run(GanttProject.java:1046)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745)
at java.awt.EventQueue.access$300(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:706)
at java.awt.EventQueue$3.run(EventQueue.java:704)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:715)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:218)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:133)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:122)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:118)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:110)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

La salida anterior corresponde al programa GanttProject que se utilizará como ejemplo.

En este caso particular el programa no muestra ninguna interfaz pero queda ejecutandose el proceso java.

La ejecución se realiza en una PC con Ubuntu 14.04

Diagnóstico

El problema está relacionado a la excepción java.awt.HeadlessException:

Thrown when code that is dependent on a keyboard, display, or mouse is called in an environment that does not support a keyboard, display, or mouse.

Se revisa el sistema buscando las JVM instaladas. En ubuntu y debian están los paquetes default-jre y default-jre-headless, los cuales dependen de la versión de java recomendada para el sistema.

$ dpkg -l 'default-jre*' | grep ^ii

Nota: jre hace referencia a Java Runtime Environment.

Si solo se lista el paquete default-jre-headless tenemos el Caso 1.

Si no se obtiene ningún paquete puede ocurrir que haya sido instalada directamente una versión particular de la JVM. Para determinar que JVM está instalada en el sistema utilizar

$ dpkg -l '*-jre*' | grep ^ii

Aquí puede suceder que solo se encuentren paquetes con el sufijo -jre-headless; este será el Caso 2. También pueden no obtenerse resultados, Caso 3, o se pueden obtener varias versiones de JVM’s, teniendose en algunos casos que solo se encuentra instalado el paquete con sufijo -jre-headless en lugar de la combinación con sufijo -jre-headless/-jre, a lo que llamaremos Caso 4.

Solución

Caso 1

En este caso si solo está instalado el paquete default-jre-headless hay que instalar además el paquete default-jre, ya que como lo indica su descripción no se incluye el soporte para aplicaciones gráficas:

$ apt-cache show default-jre-headless | sed -n '/^Description-en:/,/^\S/p'
Description-en: Standard Java or Java compatible Runtime (headless)
 This package points to the Java runtime, or Java compatible
 runtime recommended for this architecture, which is
 openjdk-7-jre-headless for i386.
 .
 The package is used as dependency for packages not needing a
 graphical display during runtime.
Description-md5: d5b4670ac6d3f132e688eb4d6e67965f

La instalación se realiza mediante:

$ sudo apt-get install -V default-jre

Caso 2

En este caso se instaló una JVM particular sin la opción para gráficos, por lo que se debe incluir el soporte para gráficos. Esto se hace instalando el paquete con sufijo -jre.

Como ejemplo si la salida del comando es:

ii  openjdk-7-jre-headless:i386                7u121-2.6.8-1ubuntu0.14.04.1            i386         OpenJDK Java runtime, using Hotspot JIT (headless)

Se debe instalar el paquete openjdk-7-jre

Caso 3

Si no se obtuvo ninguna salida esto indica que no se tiene instalada una JVM de java en el PC. Conviene instalar como se mencionó en el Caso 1 el paquete default-jre.

Caso 4

La salida del comando dpkg -l es similar a la siguiente:

ii  openjdk-7-jre-headless:i386                7u121-2.6.8-1ubuntu0.14.04.1            i386         OpenJDK Java runtime, using Hotspot JIT (headless)
ii  oracle-java7-jre                           7.80-1                                  all          Oracle Java(TM) Runtime Environment (JRE) 7 (architecture independent files)

En este caso se tiene más de una versión de JVM instalada y entra en juego el sistema de alternativas de debian.

Primero hay que saber cual es la versión por defecto en uso:

$ javac --version

o

$ update-alternatives --display java

Aquí puede pasar que la versión en uso por defecto sea la que solo tiene instalado el -jre-headless. En ese caso alcanza con instalar la versión -jre. En el ejemplo anterior openjdk-7-jre.

Otra alternativa es que la versión por defecto sea la -jre (en el caso de ejemplo oracle-java7-jre), pero el programa está utilizando la versión -jre-headless mediante el uso de JAVA_HOME o porque utiliza directamente la ruta del binario java del paquete -jre-headless. Las alternativas serían nuevamente instalar la versión del paquete -jre (en el ejemplo openjdk-7-jre) o configurar el script que ejecuta el programa para que utilice la versión de java por defecto del sistema.

Lecciones aprendidas

Siempre verificar:

  1. Si fué instalada una versión por defecto de la JVM (paquetes default-jre y default-jre-headless).
  2. Las versiones de la JVM instaladas en el sistema (paquetes -jre y -jre-headless).
  3. La JVM utilizada por el programa.

Varias distribuciones separan la JVM en varios paquetes: