Una primera revisión de los módulos incluidos en Java 9. Desde el planteamiento del problema inicial y su sintaxis con algún ejemplo de uso. Esta ponencia se ha impartido como parte de las charlas de la Semana de la Ingeniería Informática 2018 en la Escuela Politécnica Superior de la Universidad de Burgos.
1. JAVA 9 - MÓDULOS
DEL INFIERNO DE LOS JAR,AL INFIERNO DE LOS MÓDULOS
Raúl Marticorena Sánchez
Área de Lenguajes y Sistemas Informáticos
Depto. Ingeniería Civil
Grupo de Investigación Admirable
Grupo de Innovación Docente DIGIT y eNOL
Semana de la Ingeniería Informática
8 de febrero de 2018, Escuela Politécnica Superior, CampusVena
4. PRECEDENTES HISTÓRICOS
• 1991 como Oak, luego Green y finalmente Java
• Java 1.0 (mayo,1995, Sun Microsystems) presentación en SunWorld – JDK 1.0 enero 1996
• Inspirado en C++
• Write Once, Run Anywhere
• Máquina virtual
Año Versión
Febrero, 1997 JDK 1.1
Diciembre, 1998 J2SE 1.2
Mayo, 2000 J2SE 1.3
Febrero, 2002 J2SE 1.4
Septiembre, 2004 J2SE 5.0
Diciembre, 2006 Java SE 6
Julio, 2011 Java SE 7
Marzo, 2014 Java SE 8
Septiembre, 2017 Java SE 9
Genericidad
Anotaciones
Enumeraciones
Módulos
Lambdas
Inner classes
Reflexión
Asertos
Abril, 2009
4
5. COMPILACIÓNY GENERACIÓN DE BINARIOS
• Compilación: de código fuente (texto) a código “binario” (bytecodes)
• Del concepto de clases (¿módulos?) en fichero fuente (.java) al concepto de clase (.class)
• “Uno a uno” o “Uno a varios”
5
7. DISTRIBUCIÓN DE BINARIOS: FICHEROS .JAR
• La estructura de paquetes y clases (directorios y ficheros .class) se “comprime” en un fichero .jar
• Más simple de distribuir y “controlar” (no tanto ;))
java
lang
util
java
lang
util
“empaquetado”
biblioteca 1.0.jar
7
8. ¿CÓMO BUSCAR LAS CLASES?
• Concepto fundamental del CLASSPATH
• Lista de directorios de búsqueda de clases (.class)
• Ficheros .jar contenedores de paquetes y clases
• Definido como:
1. Variable de entorno del S.O
2. Como argumento al comando del JDK
biblioteca_A 1.0.jar
biblioteca_B 2.0.jar
bblioteca_C 2.3.jar
NoSuchFieldError,
NoSuchMethodError
ClassNotFoundException
NoClassDefFoundError
8
10. REALMENTE HAY UN INFIERNO…
Artista: Hieronymus Bosch (El Bosco)
El jardín de las Delicias
Museo del Prado
10
11. EL INFIERNO DE LOS JAR
• Si buscas en Google “jar hell” hay 17.900.000 resultados…
• Curiosidad: si buscas en Google “dll hell” sólo hay 1.100.000 resultados
• Problemas
• Dependencias no públicas (no explícitas)
• Dependencias transitivas
• Quizás sólo se necesita una parte del jar
• Sombreado de clases
• Conflicto de versiones
• Complicaciones con la carga dinámica de clase
• Etc.
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
biblioteca_X 1.0.0.jar
En ejecución puede haber
“sorpresas” con código
compilado correctamente 11
12. ENCAPSULACIÓN DÉBIL
• Acceso a paquetes públicos entre bibliotecas indiscriminadamente
java
lang
util
Biblioteca_X 1.0.jar
public class
java
lang
util
Biblioteca_Y 1.0.jar
Paquete
“interno”
Acceso
permitido a
detalles de
implementación
12
13. ENCAPSULACIÓN DÉBIL
• Se ha “abusado” del acceso a paquetes “no abstractos” vinculados a la implementación concreta
(JDK-internal APIs)
• Ej: com.sun.* o sun.*
• Incluso usando bibliotecas “peligrosas”:
• Ej: Uso de sun.misc.Unsafe para “cosas raras” (bajo nivel) en Java:
• Crear un objeto sin usar un constructor
• Acceso a memoria nativa
• Lanzar excepciones comprobables no declaradas
• Concurrencia nativa, etc.
• Se pueden detectar esos usos peligrosos con el comando jdeps
• Ej: jdeps --jdk-internals -R –cp lib/* mi-fichero.jar
13
14. HERRAMIENTAS AL RESCATE
• Descarga bibliotecas (.jar) y gestiona dependencias
• A partir de una declaración en formato XML
• Ej: utilizamos JUnit 4.8.2
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
14
15. HERRAMIENTAS AL RESCATE
• Tomando Ant y Maven como antecedentes
• Descarga bibliotecas (.jar) y gestiona dependencias
• A partir de una declaración en lenguaje Groovy
• Estándar “de facto” en entornos como Android Studio
• Ej: bibliotecas commons-collections y JUnit
dependencies {
compile group: 'commons-collections', name: 'commons-collections', version: '3.2.2'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
15
16. Y OTROS PROBLEMAS ADICIONALES… EL
ELEFANTE EN LA HABITACIÓN
• Distribución de las aplicaciones depende del “pequeño” JDK / JRE
• Excesivo tamaño del JDK/JRE
• Dificultando la distribución
• En particular para dispositivos con pocos recursos (pensando en IoT…)
• Solución parcial con los Compact Profiles de la versión 8 de Java SE Embedded 8
• ¿A sustituir por los módulos de Java 9?
• Curiosidad: problema en Android resuelto parcialmente con su propia MáquinaVirtual Java
• Dalvik y ART
Aplicación Java
JDK/JRE
16
18. • Proyecto Jigsaw
• Inicialmente se iba a incluir en Java 8, pero se retrasó a Java 9… (complicaciones en su inclusión… ¡6 años!)
• Objetivos
• Encapsulación más fuerte
• Definición más precisa de dependencias
• Intento de escapar del infierno de la definición del CLASSPATH (“brittle classpath”)
• Evitar errores en ejecución (NotClassDefFoundError) pese a tener código “bien compilado”
• Java SE Platform, JDK y JRE más fácilmente escalable para dispositivos con menos recursos
• Mejora de seguridad y mantenibilidad
• Permitir mejoras de rendimiento.
• Facilitar a los desarrolladores la construcción y mantenimiento de bibliotecas y aplicaciones de mayor
tamaño para Java SE y EE
• Etc.
MÓDULOS
18
19. MÓDULOS
• Se define DECLARATIVAMENTE un fichero module-info.java que indica:
• 1) Nombre único del modulo (Ej: java.base, java.xml, java.logging, etc.)
• 2) Módulos de los que depende
• 3) Paquetes exportados para su uso por otros módulos
• Y alguna otra cosa…
• Al compilarse se generará el correspondiente module-info.class.
• Aparece otro elemento externo muy importante… el MODULE-PATH
Pero el
CLASSPATH
también sigue
existiendo…
19
21. MÓDULOS
• A) Exportan paquetes (exports)
• Sólo las clases públicas de paquetes exportados son visibles en compilación
y ejecución
• El resto de clases públicas del modulo ya NO son accesibles
• B) Declararan dependencias de uso (requires) de paquetes
exportados de otros módulos (en compilación y ejecución)
21
22. CREANDO UN MÓDULO
• Convención de nombres similar a los paquetes (nombre de dominio inverso)
• Pero sin correspondencia con directorios y subdirectorios
• Ej: es.ubu.lsi se corresponde con un directorio raíz de nombre es.ubu.lsi
• NO con una estructura de árbol de directorio es, subdirectorio ubu y subdirectorio lsi.
• En el directorio raíz se incluye un fichero module-info.java
• El nombre del módulo debe coincidir con el nombre del directorio “raíz” que lo contiene
• Curiosidad: similar al caso de los package-info.java por paquete, aunque estos sólo cumplen un papel de
documentación
• Dentro de dicho directorio raíz tendremos una estructura de paquetes:
• Normalmente se corresponde parcialmente a su vez con lo indicado en el nombre de módulo
• NO es obligatoria esa correspondencia (aunque algunas fuentes bibliográficas lo recomiendan para evitar colisiones de nombres)
• En concreto se dice que coincida con el “principal exported API package,”
Esto puede crear una
cierta confusión…
+- es.ubu.lsi
+- es
+- ubu
+- lsi
22
23. CREANDO UN MÓDULO
• Ejemplo:
src
+- es.ubu.lsi
+- module-info.java
+- es
+- ubu
+- lsi
+- util
+- Log.java
Nombre del módulo
Estructura de paquetes, en
correspondencia con el
nombre de módulo. NO es
obligatorio que coincida.
Fichero con el nombre de
módulo, módulos requeridos
y exportaciones de paquetes
Otros paquetes y ficheros
fuente del módulo
23
OJO, ejemplo
pensado para
multimódulo
24. CONTENIDO DE MODULE-INFO.JAVA
• Ejemplo: module-info.java
module es.ubu.lsi {
exports es.ubu.lsi.control;
exports es.ubu.lsi.control.impl to es.ubu.comp;
requires es.ubu.ingciv;
}
Requiere acceso a este módulo.
Permite acceder a paquetes
exportados de dicho módulo. Otros
módulos que dependan de éste NO
tienen acceso (NO transitivo)
Nombre del módulo
Exportación de paquetes.
Necesario exportar subpaquetes,
explícitamente
Exportación calificada de
subpaquete a un único módulo,
es.ubu.comp en el ejemplo.
24
25. COMPILACIÓN: JAVAC
• Para compilar se indica el directorio de destino del módulo:
• Se puede indicar la localización de directorios contenedores de módulos:
• Con el parámetro --module-path o –p.
• Si son varios directorios se usa el separador (; o :) igual que con el classpath.
javac –d bin/nombre.modulo @listaFicheros
javac –-module-path bin –d bin/nombre.modulo
@listaFicheros
25
26. MODOS DE COMPILACIÓN
• A) Legado: usando básicamente el classpath, sin módulos explícitos
(Java 8 o anteriores)
• Todo el código en el unnamed module
• B) Módulo simple
• Sólo existe un módulo en el directorio de fuentes (src)
• Puede ser necesario utilizar --module-path para compilar y ejecutar
• C) Multi módulo
• Varios módulos (directorios) en el directorio de fuentes (src)
• Indicando en compilación el directorio con --module-source-path
|
---src
| module-info.java
|
---ubu
---lsi
MiClase.java
---src
+---data.access
| | module-info.java
| |
| ---data
| Util.java
|
---ui.app
| module-info.java
|
---app
Main.java
26
27. EJECUCIÓN: JAVA
• Se indica además la clase raíz en el módulo correspondiente con la opción –m (o --module):
• Ej:
• Se puede indicar la localización de módulos con el parámetro --module-path o –p
• Si el módulo está contenido en un fichero .jar creado con la opción --main-class no es
necesario indicar la clase raíz
• Ej:
java –-module-path bin –m nombre.modulo/paquete.subpaquete.ClaseRaiz
java –-module-path bin –-module nombre.modulo/paquete.subpaquete.ClaseRaiz
java –-module-path bin –-module nombre.modulo
27
28. EMPAQUETADO: JAR
• Como en versiones previas, se sigue utilizando el comando jar
• Necesario empaquetar cada módulo en su .jar
• Incluso con solución multimódulo
• Ej:
• Podemos ver su contenido (ficheros contenidos) con la opción --list
• Podemos ver su dependencias y exportaciones con --describe-module
• Ej:
jar -c -f mlibhola.mundo.proveedor.jar -C outputhola.mundo.proveedor .
jar --describe-module --file mlibhola.mundo.proveedor.jar
hola.mundo.proveedor jar:file:///C:/directorio/HolaMundo/mlib/hola.mundo.proveedor.jar/!module-info.class
exports es.ubu.lsi
requires java.base mandated
28
Ahora con un parámetro
--module-version
simplemente informativo
29. JDK API EN JAVA 9
• El propio JDK 9 tiene ahora una estructura modular
• Sus clases se organizan en paquetes y módulos
• TODOS los módulos importan implícitamente el módulo java.base.
• Se recomienda revisar en <jdk-home>/src.zip la estructura actual.
• Documentación en línea:
• https://docs.oracle.com/javase/9/docs/api/overview-summary.html
29
30. JDK API EN JAVA 9
Módulo por defecto para
todos
30
31. TIPOS DE MÓDULOS
• 1) Módulo de aplicación con nombre (Named Application Module)
• Contienen un fichero module-info.class con su definición
• Incluidos en el MODULE-PATH
• Exportan paquetes explícitamente
• Requieren (leen) módulos explícitamente
• No pueden requerir (leer) del módulo unnamed (no tiene nombre… evitamos depender del CLASSPATH)
• 2) Automáticos
• Ficheros .jar NO modularizados (sin module-info.class) que se incluyen al MODULE-PATH
• Necesarios para permitir la migración de bibliotecas pre-Java 9
• ExportanTODOS sus paquetes implícitamente (también abiertos para reflexión…)
• Requieren (leen)TODOS los módulos implícitamente
• Java 9 genera un nombre de módulo automático:
• A partir del nombre del fichero .jar o del Automatic-Module-Name en el MANIFEST.MF
• Eliminando los números de versión (si existen) y reemplazando otros caracteres no alfanuméricos por puntos:
• Ej: mongo-java-driver-3.3.0.jar mongo.java.driver
.jar Pre-Java 9 en
MODULE_PATH
Módulo Java 9 en
MODULE_PATH
31
32. TIPOS DE MÓDULOS
• 3) Módulo sin nombre (Unnamed Module)
• Todos los .jar (modulares o no) y clases directamente en el CLASSPATH (estarán contenidos en un
“Unnamed Module”)
• Exportan TODOS sus paquetes implícitamente (también abiertos para reflexión…)
• Requieren (leen) TODOS los módulos implícitamente
• Al NO tener nombre, NO puede ser requerido en otros módulos.
• 4) De plataforma (Platform Module)
• Módulos propios del JDK
• Resultado de la propia reestructuración de Java 9 en módulos
• Ej: java.base como módulo básico
Módulo Java 9 o
.jar Pre-Java 9 y
clases en el
CLASSPATH
Módulos
JDK
32
33. ACCESO ENTRE TIPOS DE MÓDULOS
Tipo Origen Exporta (exports)
paquetes
Puede leer (requires)
módulos de..
Módulo de
aplicación con
nombre
Cualquier JAR conteniendo un
module-info.class
en el module-path
Explícitamente Aplicación con nombre
Automático
Plataforma
Automáticos
Cualquier JAR sin
module-info.class
en el module-path
Implícitamente todos
Aplicación con nombre
Automático
Sin nombre (unnamed)
Plataforma
Sin nombre Todos los JAR y clases en el
classpath
Implícitamente todos Aplicación con nombre
Automáticos
Plataforma
De plataforma Dentro del JDK Explícitamente -
33
34. EL MÓDULO “SIN NOMBRE”: UNNAMED MODULE
• Similar al paquete por defecto (default package)
• Formado por clases y paquetes NO contenidos en módulos (módulo por defecto) sino en el CLASSPATH
• Ej: todo el código Java 8 o previo que no se ha migrado (ni se migrará) a módulos Java 9
• Requiere:
• Implícitamente todo módulo con nombre (bajo demanda, si lo necesitan)
• Pueden leer cualquier módulo (con o sin nombre)
• Clases Java 8 (o anteriores) pueden leer cualquier módulo Java 9
• Continuarán “funcionando” en Java 9 tanto en compilación como ejecución
• Exporta:
• Todos los paquetes implícitamente
• Accesibles sólo para el módulo sin nombre
• No se puede “requerir” desde otros módulos con nombre, porque NO tiene nombre
34
Java sigue cuidando mucho la
ejecución de código “antiguo”
sobre la nueva versión
(backward)…no al revés
35. EL MÓDULO “SIN NOMBRE”: UNNAMED MODULE
• Con el comando jdeps se pueden mostrar las dependencias de clases en el unnamed
module
• Nota o curiosidad: con una variante jdepscan para detectar uso de APIs deprecated
(análisis estático)
jdeps –s .bin
35
36. OTRA RAREZA: MÓDULOS RAÍZ (ROOT MODULE)
• Módulos sin clases ni paquetes, sólo module-info.java…
• Ej: módulo java.se
• Indica dependencias TRANSITIVAS
• Hace disponibles esos módulos para aquellos que requieren de
java.se
• NO es lo mismo que exportar paquetes
• Al compilar el unnamed module, suele estar disponible un
módulo raíz por defecto:
• En JDK 9, el módulo java.se
• Para cargar clases fuera de este grafo de módulos añadimos al
compilar o ejecutar:
• --add-modules nombre.modulo
module java.se {
requires transitive java.compiler;
requires transitive java.datatransfer;
requires transitive java.desktop;
requires transitive java.instrument;
requires transitive java.logging;
requires transitive java.management;
requires transitive java.management.rmi;
requires transitive java.naming;
requires transitive java.prefs;
requires transitive java.rmi;
requires transitive java.scripting;
requires transitive java.security.jgss;
requires transitive java.security.sasl;
requires transitive java.sql;
requires transitive java.sql.rowset;
requires transitive java.xml;
requires transitive java.xml.crypto;
}
36
37. EL PROBLEMA DE LA ENCAPSULACIÓN DÉBIL
PUBLIC ES DEMASIADO PUBLIC
• ¿Qué teníamos hasta ahora?
• Clases e interfaces de nivel superior: public o “amigable” (privado a nivel de paquete)
• Nota: en clases e interfaces anidadas (dentro de otras) se puede usar además private o protected como con el resto
de miembros de la clase
• Encapsulación débil (Weak Encapsulation)
• Los módulos introducen el concepto de encapsulación fuerte (Strong Encapsulation)
• Clases públicas ya NO son accesibles desde otros módulos (y desde sus paquetes)
• Ahora:
• Sólo los tipos y propiedades públicas de los paquetes exportados son accesibles
• Sólo son accesibles a los módulos que requieren dicho modulo
• Otro nuevo nivel de acceso y encapsulación en Java
37
38. PROBLEMAS DEL USO DE MÓDULOS
• Ahora NO todos los paquetes de los módulos de Java 9 son accesibles
• Tip: --jdk-internals con jdeps…
• Pero se puede “puentear” el sistema en línea de comandos:
• Ejemplo: supongamos que usamos clases del paqute sun.security.util y
sun.security.x509 desde un .jar pre-Java 9 (no modular)
java -jar miaplicacion.jar ^
--add-exports java.base/sun.security.util=ALL-UNNAMED ^
--add-exports java.base/sun.security.x509=ALL-UNNAMED
módulo Todos los módulos en el grafo de
módulos y clases/jar del CLASSPATH
paquete
38
Por el momento se
permite con
“avisos” pero en un
futuro…
39. ¿Y QUÉ OCURRE CON LA “REFLEXIÓN”?
• Java Reflection API permite la inspección y manipulación de clases e interfaces (métodos y atributos)
en tiempo de ejecución
• Sin conocer a priori (en tiempo de compilación) los tipos y/o nombres de las clases (con sus riesgos)
• Fundamento de muchas bibliotecas muy útiles (Ej: Hibernate, JUnit,, Spring, etc.)
• Uso avanzado que permite también “saltar barreras” (Ej: ¿acceso a private?, ¿modificar un final?
Etc.)
• Ejemplo:
Integer dos = 2; // auto-boxing, inmutable
Field value = Integer.class.getDeclaredField("value");
value.setAccessible(true); // "eliminamos" el final
value.set(dos, 3); // cambiamos el valor
if (1 + 1 != dos) {
System.out.println("¡La hemos liado!");
}
39
40. ¿Y QUÉ OCURRE CON LA “REFLEXIÓN”?
• Por defecto:AHORA la reflexión está “cerrada” entre módulos.
• Sólo cuestiones básicas: Ej: Class.forName(…), Class.getDeclaredFields(), etc.
• No uso de métodos sobre clase Field, Constructor, etc. (en java.lang.reflect)
• Se puede “abrir” el acceso (total) sobre:
• Módulo (open)
• Paquete (opens)
• Paquete para módulos concretos (opens to)
• Adicionalmente desde línea de comandos con.
• Finalmente con opción (deprecated)
open module client.module{
requires framework.module;
}
module client.module{
opens some.client.package;
requires framework.module;
}
module client.module{
opens some.client.package to framework.module;
requires framework.module;
}
Ejemplo
–-add-opens modulo/paquete=modulo
--permit-illegal-access paquete.Clase
40
41. ROMPIENDO LA ENCAPSULACIÓN FUERTE
• Opciones en compilación y ejecución:
• --add-exports $module/$package=$readingmodule
• Exporta el paquete al modulo indicado.
• Si se establece $readingmodule a ALL-UNNAMED, todos los módulos en el grafo de módulos, y
el código del CLASSPATH puede accede al paquete. Disponible en compilación y ejecución.
• --add-opens $module/$package=$readingmodule
• Abre el acceso completo con reflexión del paquete al módulo indicado.
• Abre el paquete para reflexión profunda (deep reflection), todos sus tipos y miembros son accesibles con
independencia de su modificador de acceso (incluso privados).
41
42. MIGRACIÓN DE FICHERO JAR NO
MODULARIZADO A MÓDULO
• Recordemos: módulos “automáticos”
• Facilitar la migración de ficheros.jar NO modularizados “sin tocarlos mucho”
• Modificando el fichero MANIFEST.MF se puede “extender” para comportarse como
un módulo
• Atributos nuevos:
• Automatic-Module-Name: module.name – declara un nombre de módulo para un .jar no
modularizado
• Add-Exports: module/package – exporta el paquete de dicho módulo a todos los módulos sin
nombre (unnamed modules)
• Add-Opens: module/package – abre el paquete de dicho módulo a todos los módulos sin nombre
(unnamed modules)
42
43. SITUACIÓN PARA LA MIGRACIÓN
• Transición de Java pre-9 Java 9 con:
• .class,
• .jar NO modularizados
• .jar semi-modularizados,
• .jar modularizados
• .jmod
• Etc.
• Con dos “infiernos” a manejar:
• --class-path
• --module-path
43
44. PROSY CONTRAS DE LOS MÓDULOS
• Configuración “fiable”
• Búsqueda de módulos frente a búsqueda individual de clases con el CLASSPATH:
• En tiempo de lanzamiento, NO en tiempo de ejecución (Launch-time vs. Runtime)
• Resolución transitiva de dependencias entre módulos
• Frente al problema de las dependencias no explícitas y transitivas sin fin, con el CLASSPATH
• Detección de sombreado de paquetes inmediata entre módulos
• Mejora importante en la encapsulación
• Mínimas dependencias entre módulos facilitando su evolución
• NO se especifica número de versión de módulo:
• ¡NO RESUELVE LOS PROBLEMAS DELVERSIONADO! (¿MODULE-HELL?)
• Nota: OSGI sí que resuelve esto…
44
45. SE DEJA PENDIENTE EL PROBLEMA DE LAS
VERSIONES…
• The State of the Module System (2016) Mark Reinhold.
http://openjdk.java.net/projects/jigsaw/spec/sotms/
“A module’s declaration does not include a version
string, nor constraints upon the version strings of the
modules upon which it depends.This is intentional: It is not
a goal of the module system to solve the version-
selection problem, which is best left to build tools and
container applications.”
45
46. SE DEJA PENDIENTE EL PROBLEMA DE LAS
VERSIONES…
• Java Platform Module System: Requirements. DRAFT 2 (2015) Mark Reinhold
• http://openjdk.java.net/projects/jigsaw/spec/reqs/02
“In other words, this specification need not define yet another
dependency-management mechanism. Maven, Ivy, and Gradle
have all tackled this difficult problem.We should leave it to these
and other build tools, and container applications, to discover and
select a set of candidate modules for a given library or application. The
module system need only validate that the set of selected
modules satisfies each module’s dependences.”
46
47. ¿REACCIONES?
• IBM y RedHat no están contento (y Oracle responde) – mayo, 2017
• https://www.infoq.com/news/2017/05/no-jigsaw
• https://www.infoworld.com/article/3194367/java/java-module-system-may-stall-platforms-next-release.html
• https://www.infoworld.com/article/3194759/java/oracle-hits-back-at-modular-java-critics.html
• Con una “tibia” acogida –mayo-abril, 2017
• http://mydailyjava.blogspot.com.es/2017/05/yet-another-jigsaw-opinion-piece.html
• https://www.infoworld.com/article/3188454/java/the-true-impact-of-modular-java.html
• O muy “tibia” – julio, 2017
• https://jaxenter.com/java-influencers-interview-2-135720.html
• http://blog.joda.org/2017/05/java-se-9-jpms-automatic-modules.html
• Y alguna ligera “bienvenida” – noviembre, 2017
• https://www.darwinrecruitment.com/blog/2017/11/java-9-review-what-was-all-the-fuss-about#
47
49. SERVICIOSY PROVEEDORES DE SERVICIO
• Módulos desarrollados como Servicios y Proveedores de servicios:
• A) Un modulo consumidor de servicio declara que usa (uses) una o más interfaces de servicio
• Su implementación concreta será proporcionada en tiempo de ejecución por un modulo proveedor
• B) Un modulo proveedor de servicio declara qué implementación concreta de la interfaz de
servicio proporciona (provides … with…)
• El cliente NO declara nada respecto al proveedor:
• En tiempo de ejecución se indica el proveedor, como módulo adicional, en el module-path.
• En el código del cliente se usa la API (ServiceLoader#load(AnInterface.class)) para
obtener la implementación concreta disponible
49
Proveedor Cliente
50. SERVICIOSY PROVEEDORES DE SERVICIO
• Otra opción: en el módulo proveedor de servicio se proporciona una clase
proveedora que implementa un método público estático de nombre
'provider()’
• Dicho método retorna una instancia de la implementación del servicio
• La clase proveedora NO implementa directamente la interfaz
• Su método provider retorna un objeto de ese tipo
• En el fichero module-info.java del proveedor, en la cláusula provides … with…
• Se cambia en el with el nombre de la clase de implementación, por la clase proveedora.
• Ventajas:
• Más control sobre la inicialización de la implementación del servicio
50
51. SERVICIOS DESACOPLADOS: USO DE SERVICE
LOADER
• Ejemplo: module-info.java
module es.ubu.lsi.log.service {
requires es.ubu.lsi.service;
exports es.ubu.lsi.log.service;
provides es.ubu.lsi.service.LogService
with es.ubu.lsi.log.service.LogService;
}
Módulo proveedor:
provee la implementación
de un servicio
module es.ubu.lsi.consumer {
requires es.ubu.lsi.service;
uses es.ubu.lsi.service.LogService;
}
// Carga del proveedor en código…
ServiceLoader.load(EventService.class);
// load retorna un Iterable<T> con la
lista de proveedores de dicha interfaz
dada por los módulos disponibles
Módulo consumidor: sin conocer el
módulo ni la clase que provee la
implementación del servicio
51
52. SPLIT PACKAGES
• Paquetes con mismo nombre en distintas aplicaciones/librerías (.jar)
• En Java pre-9 se permite
• NO se permiten en los módulos (ni siquiera con paquetes no exportados)
• Error generado en ejecución (en lanzamiento) NO en compilación
• SÍ se permite con el unnamed module (por compatibilidad hacia atrás)
52
53. VOLVIENDO AL ELEFANTE EN LA HABITACIÓN
• La distribución y ejecución de las aplicaciones depende del JRE (Java Runtime Environment)
• Reducción del tamaño de los “ejecutables”
• Previamente en Java: enlazado (“linkado”) dinámico
• En Java 9 se puede enlazar estáticamente:
• A) Herramientas de enlazado estático
• Creando “imágenes” ejecutables
• B) Herramientas de creación de jmod
• Módulos en formato jmod
JRE
Java App
53
54. NUEVAS HERRAMIENTAS: JLINK
• ¡En Java 9 se puede “linkar” !
• Fase posterior a la compilación generando una “imagen “ejecutable”
• OJO: NO genera un “ejecutable” (.exe, .bin, etc.)
• Genera una estructura de directorios “ejecutable”
• TODOS los ficheros necesarios (JRE “customizado”)
• Ejemplo: generar y ejecutar un “Hola mundo”
jlink [options] --module-path modulepath --add-modules module [,module...]
├───bin
│ └───server
├───conf
│ └───security
│ └───policy
│ ├───limited
│ └───unlimited
├───include
│ └───win32
├───legal
│ └───java.base
└───lib
├───security
└───server
jlink --module-path %JAVA_HOME%jmods;.mlib --add-modules
hola.mundo.simple --output app
// nos movemos al directorio .appbin y ejecutamos
java -m hola.mundo.simple/es.ubu.lsi.HolaMundo
Windows
54
55. NUEVAS HERRAMIENTAS: JLINK
• Ejemplo: generar y ejecutar un “Hola mundo” con un lanzador
jlink --module-path %JAVA_HOME%jmods;.mlib --add-modules hola.mundo.simple --output app --launcher
launch= hola.mundo.simple/es.ubu.lsi.HolaMundo
// nos movemos al directorio .appbin y ejecutamos
launch
├───bin
│ └───server
├───conf
│ └───security
│ └───policy
│ ├───limited
│ └───unlimited
├───include
│ └───win32
├───legal
│ └───java.base
└───lib
├───security
└───server
Imagen de unos 36
MB en Windows…
55
56. NUEVAS HERRAMIENTAS: JMOD
• Nuevo formato de fichero JMOD
• Creados con el comando jmod:
• Pensados para:
• Módulos con bibliotecas nativas u otros ficheros de configuración (no adecuados o compatibles en un .jar)
• Módulos para enlazar (linkar) a una imagen ejecutable
• NO sustituye al formato .jar
• El propio JDK distribuye ficheros jmod:
• Ver: %JAVA_HOME/jmods
• Se pueden crear y distribuir nuestros propios módulos en este formato
• Ej:
jmod (create|extract|list|describe|hash) [options] jmod-file
jmod create --class-path mods/com.greetings --cmds commands
--config configfiles --header-files src/h --libs lib
--main-class com.greetings.Main --man-pages man --module-version 1.0
--os-arch "x86_x64" --os-name "Mac OS X"
--os-version "10.10.5" greetingsmod
56
60. CRÉDITOS
60
Autor: Raúl Marticorena Sánchez
Reconocimiento – NoComercial – CompartirIgual (by-nc-sa): No se permite un
uso comercial de la obra original ni de las posibles obras derivadas, la distribución de las
cuales se debe hacer con una licencia igual a la que regula la obra original.
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-
CompartirIgual 4.0 Internacional.