SlideShare ist ein Scribd-Unternehmen logo
1 von 60
Downloaden Sie, um offline zu lesen
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
TABLA DE CONTENIDOS
•Planteamiento del problema
•Módulos
•Otras cuestiones adicionales (*)
•Ejemplos
2
PLANTEAMIENTO DEL PROBLEMA
De dónde venimos y a dónde vamos en Java
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
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
ORGANIZACIÓN LÓGICA/FÍSICA EN
PAQUETES/DIRECTORIOS
• Al igual que los ficheros de un disco duro…
Ficheros .class
(binarios)
java
lang
util
paquete
subpaquete
subpaquete
clase
6
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
¿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
¡Java es guay!
9
REALMENTE HAY UN INFIERNO…
Artista: Hieronymus Bosch (El Bosco)
El jardín de las Delicias
Museo del Prado
10
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
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
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
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
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
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
MÓDULOS
Objetivos
Sintaxis.Tipos y acceso
Encapsulación fuerte
¿Y qué ocurre con la reflexión?
Migración
Pros y contras… con temas pendientes
17
• 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
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
MÓDULOS
Imágenes extraídas de: http://www.codenuclear.com/java-9-modularity-and-jigsaw-project/
20
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
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
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
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
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
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
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
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
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
JDK API EN JAVA 9
Módulo por defecto para
todos
30
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
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
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
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
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
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
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
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…
¿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
¿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
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
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
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
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
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
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
¿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
OTRAS CUESTIONES ADICIONALES
Servicios
Detección de Split Packages
Enlazado (Link)
48
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
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
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
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
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
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
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
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
BIBLIOGRAFÍA
• Documentación en línea de Java 9 (2017) Oracle © https://docs.oracle.com/javase/9/index.html
• Getting Started with Java 9 Modules - ConSol Labs. (2017) Jens Klingen. 13 de febreo de 2017.
https://labs.consol.de/development/2017/02/13/getting-started-with-java9-modules.html#how-to-declare-a-java-9-module
• Java 9 Modules Quick Start Example (2017) http://www.logicbig.com/tutorials/core-java-tutorial/modules/quick-start/
• Musings about Jigsaw – The Java 9 Module System (2017) Sebastian Zarnekow. https://blogs.itemis.com/en/musings-about-jigsaw-
the-java-9-module-system
• Reflection vs Encapsulation - blog@CodeFX (2017) https://blog.codefx.org/java/reflection-vs-encapsulation/
• The State of the Module System (2016) Mark Reinhold. http://openjdk.java.net/projects/jigsaw/spec/sotms/
• Nota: deprecated, aunque los conceptos fundamentales no han cambiado, la sintaxis sí.
• Understanding Java 9 Modules (2017) Paul Deitel. https://www.oracle.com/corporate/features/understanding-java-9-modules.html
• WillThere Be Module Hell? (2017) https://blog.codefx.org/java/dev/will-there-be-module-hell/
57
ALGUNOS RECURSOS DE INTERÉS
• Java 9:The Modular Java Platform and Project Jigsaw
• https://www.youtube.com/watch?v=y8bpKYDrF5I
• Java Platform Module System Cheat Sheet (2017) Oleg Shelajev. ZeroTurnaround. Disponible en https://zeroturnaround.com/rebellabs/java-9-
modules-cheat-sheet/
• PDF descargable: http://files.zeroturnaround.com/pdf/RebelLabs-Java-9-modules-cheat-sheet.pdf
• Java Platform, Standard Edition Oracle JDK 9 Migration Guide (2018) Oracle
• Disponible en: https://docs.oracle.com/javase/9/migrate/toc.htm
• Modular Development with JDK 9
• https://www.youtube.com/watch?v=gtcTftvj0d0
• Modules in One Lesson by Mark Reinhold
• https://www.youtube.com/watch?v=rFhhLXcOBsk
• Project Jigsaw in JDK 9: Modularity ComesTo Java - Simon Ritter
• https://www.youtube.com/watch?v=Ks7J_qQVR7Y
58
¡MUCHAS GRACIAS POR SU ATENCIÓN!
59
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.

Weitere ähnliche Inhalte

Was ist angesagt?

Analisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A ObjetosAnalisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A Objetos
yoiner santiago
 
Ingeniería de sistemas en las organizaciones
Ingeniería de sistemas en las organizacionesIngeniería de sistemas en las organizaciones
Ingeniería de sistemas en las organizaciones
resumenesdelima
 
Diagramas de paquetes
Diagramas de paquetesDiagramas de paquetes
Diagramas de paquetes
Moises Cruz
 
Unidad 1.3 Analisis De Requerimientos
Unidad 1.3 Analisis De RequerimientosUnidad 1.3 Analisis De Requerimientos
Unidad 1.3 Analisis De Requerimientos
Sergio Sanchez
 
Componentes y Librerías - Tópicos avanzados de programación.
Componentes y Librerías - Tópicos avanzados de programación.Componentes y Librerías - Tópicos avanzados de programación.
Componentes y Librerías - Tópicos avanzados de programación.
Giancarlo Aguilar
 
SISTEMAS BASADOS EN CONOCIMIENTOS
SISTEMAS BASADOS EN CONOCIMIENTOSSISTEMAS BASADOS EN CONOCIMIENTOS
SISTEMAS BASADOS EN CONOCIMIENTOS
LUIS5111987
 
Uml lenguaje unificado de modelado
Uml lenguaje unificado de modeladoUml lenguaje unificado de modelado
Uml lenguaje unificado de modelado
Marvin Zumbado
 
Diagramas de clases y actividades
Diagramas de clases y actividadesDiagramas de clases y actividades
Diagramas de clases y actividades
TerryJoss
 
Diagrama entidad-relacion normalización
Diagrama entidad-relacion normalizaciónDiagrama entidad-relacion normalización
Diagrama entidad-relacion normalización
cintiap25
 

Was ist angesagt? (20)

Analisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A ObjetosAnalisis Y DiseñO Orientado A Objetos
Analisis Y DiseñO Orientado A Objetos
 
Modelado Orientado a Objetos
Modelado Orientado a ObjetosModelado Orientado a Objetos
Modelado Orientado a Objetos
 
Oracle
OracleOracle
Oracle
 
Ingeniería de sistemas en las organizaciones
Ingeniería de sistemas en las organizacionesIngeniería de sistemas en las organizaciones
Ingeniería de sistemas en las organizaciones
 
Diagramas de paquetes
Diagramas de paquetesDiagramas de paquetes
Diagramas de paquetes
 
 Diagramas uml de sistema de cajero automático
 Diagramas uml de sistema de cajero automático Diagramas uml de sistema de cajero automático
 Diagramas uml de sistema de cajero automático
 
Unidad 1.3 Analisis De Requerimientos
Unidad 1.3 Analisis De RequerimientosUnidad 1.3 Analisis De Requerimientos
Unidad 1.3 Analisis De Requerimientos
 
Componentes y Librerías - Tópicos avanzados de programación.
Componentes y Librerías - Tópicos avanzados de programación.Componentes y Librerías - Tópicos avanzados de programación.
Componentes y Librerías - Tópicos avanzados de programación.
 
Requerimientos Funcionales y No Funcionales
Requerimientos Funcionales y No FuncionalesRequerimientos Funcionales y No Funcionales
Requerimientos Funcionales y No Funcionales
 
Ejercicio 2
Ejercicio 2Ejercicio 2
Ejercicio 2
 
Programacion 3 unidad ii
Programacion 3   unidad iiProgramacion 3   unidad ii
Programacion 3 unidad ii
 
Proceso del Software
Proceso del Software Proceso del Software
Proceso del Software
 
SISTEMAS BASADOS EN CONOCIMIENTOS
SISTEMAS BASADOS EN CONOCIMIENTOSSISTEMAS BASADOS EN CONOCIMIENTOS
SISTEMAS BASADOS EN CONOCIMIENTOS
 
Uml lenguaje unificado de modelado
Uml lenguaje unificado de modeladoUml lenguaje unificado de modelado
Uml lenguaje unificado de modelado
 
Cuestionario
CuestionarioCuestionario
Cuestionario
 
Ejemplo manual de usuario
Ejemplo manual de usuarioEjemplo manual de usuario
Ejemplo manual de usuario
 
Diagramas de clases y actividades
Diagramas de clases y actividadesDiagramas de clases y actividades
Diagramas de clases y actividades
 
Diagrama entidad-relacion normalización
Diagrama entidad-relacion normalizaciónDiagrama entidad-relacion normalización
Diagrama entidad-relacion normalización
 
Calculo de aproximaciones usando la diferencial
Calculo de aproximaciones usando la diferencialCalculo de aproximaciones usando la diferencial
Calculo de aproximaciones usando la diferencial
 
6 Curso de POO en Java - clases y objetos
6  Curso de POO en Java - clases y objetos6  Curso de POO en Java - clases y objetos
6 Curso de POO en Java - clases y objetos
 

Ähnlich wie Java 9 - Módulos

Programar java 2pre
Programar java 2preProgramar java 2pre
Programar java 2pre
jtk1
 
Manual de javapre
Manual de javapreManual de javapre
Manual de javapre
jtk1
 
09. Java desde Cero autor UNAM_1.111.pdf
09. Java desde Cero autor UNAM_1.111.pdf09. Java desde Cero autor UNAM_1.111.pdf
09. Java desde Cero autor UNAM_1.111.pdf
Irene619127
 

Ähnlich wie Java 9 - Módulos (20)

Entornodedesarrollodejava
EntornodedesarrollodejavaEntornodedesarrollodejava
Entornodedesarrollodejava
 
Curso Java Resumen - Curso 2005-2006
Curso Java Resumen - Curso 2005-2006Curso Java Resumen - Curso 2005-2006
Curso Java Resumen - Curso 2005-2006
 
Java desde cero
Java desde ceroJava desde cero
Java desde cero
 
1.introduccion java
1.introduccion java1.introduccion java
1.introduccion java
 
Programar java 2pre
Programar java 2preProgramar java 2pre
Programar java 2pre
 
Manual de javapre
Manual de javapreManual de javapre
Manual de javapre
 
09. Java desde Cero autor UNAM_1.111.pdf
09. Java desde Cero autor UNAM_1.111.pdf09. Java desde Cero autor UNAM_1.111.pdf
09. Java desde Cero autor UNAM_1.111.pdf
 
Programación con java en Eclipse
Programación con java en EclipseProgramación con java en Eclipse
Programación con java en Eclipse
 
Cap7 modularidad
Cap7 modularidadCap7 modularidad
Cap7 modularidad
 
01 - Introducción
01 - Introducción01 - Introducción
01 - Introducción
 
JAVA 2
JAVA 2JAVA 2
JAVA 2
 
MANUAL DE JAVA
MANUAL DE JAVAMANUAL DE JAVA
MANUAL DE JAVA
 
Java desde cero
Java desde ceroJava desde cero
Java desde cero
 
MANUAL JAVA
MANUAL JAVA MANUAL JAVA
MANUAL JAVA
 
JAVA
JAVA JAVA
JAVA
 
Programación Modular con Java 9
Programación Modular con Java 9Programación Modular con Java 9
Programación Modular con Java 9
 
Lenguaje java
Lenguaje javaLenguaje java
Lenguaje java
 
Lenguaje Java
Lenguaje JavaLenguaje Java
Lenguaje Java
 
Java desde cero
Java desde ceroJava desde cero
Java desde cero
 
Manual de Java
Manual de JavaManual de Java
Manual de Java
 

Java 9 - Módulos

  • 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
  • 2. TABLA DE CONTENIDOS •Planteamiento del problema •Módulos •Otras cuestiones adicionales (*) •Ejemplos 2
  • 3. PLANTEAMIENTO DEL PROBLEMA De dónde venimos y a dónde vamos en Java
  • 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
  • 6. ORGANIZACIÓN LÓGICA/FÍSICA EN PAQUETES/DIRECTORIOS • Al igual que los ficheros de un disco duro… Ficheros .class (binarios) java lang util paquete subpaquete subpaquete clase 6
  • 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
  • 17. MÓDULOS Objetivos Sintaxis.Tipos y acceso Encapsulación fuerte ¿Y qué ocurre con la reflexión? Migración Pros y contras… con temas pendientes 17
  • 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
  • 20. MÓDULOS Imágenes extraídas de: http://www.codenuclear.com/java-9-modularity-and-jigsaw-project/ 20
  • 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
  • 48. OTRAS CUESTIONES ADICIONALES Servicios Detección de Split Packages Enlazado (Link) 48
  • 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
  • 57. BIBLIOGRAFÍA • Documentación en línea de Java 9 (2017) Oracle © https://docs.oracle.com/javase/9/index.html • Getting Started with Java 9 Modules - ConSol Labs. (2017) Jens Klingen. 13 de febreo de 2017. https://labs.consol.de/development/2017/02/13/getting-started-with-java9-modules.html#how-to-declare-a-java-9-module • Java 9 Modules Quick Start Example (2017) http://www.logicbig.com/tutorials/core-java-tutorial/modules/quick-start/ • Musings about Jigsaw – The Java 9 Module System (2017) Sebastian Zarnekow. https://blogs.itemis.com/en/musings-about-jigsaw- the-java-9-module-system • Reflection vs Encapsulation - blog@CodeFX (2017) https://blog.codefx.org/java/reflection-vs-encapsulation/ • The State of the Module System (2016) Mark Reinhold. http://openjdk.java.net/projects/jigsaw/spec/sotms/ • Nota: deprecated, aunque los conceptos fundamentales no han cambiado, la sintaxis sí. • Understanding Java 9 Modules (2017) Paul Deitel. https://www.oracle.com/corporate/features/understanding-java-9-modules.html • WillThere Be Module Hell? (2017) https://blog.codefx.org/java/dev/will-there-be-module-hell/ 57
  • 58. ALGUNOS RECURSOS DE INTERÉS • Java 9:The Modular Java Platform and Project Jigsaw • https://www.youtube.com/watch?v=y8bpKYDrF5I • Java Platform Module System Cheat Sheet (2017) Oleg Shelajev. ZeroTurnaround. Disponible en https://zeroturnaround.com/rebellabs/java-9- modules-cheat-sheet/ • PDF descargable: http://files.zeroturnaround.com/pdf/RebelLabs-Java-9-modules-cheat-sheet.pdf • Java Platform, Standard Edition Oracle JDK 9 Migration Guide (2018) Oracle • Disponible en: https://docs.oracle.com/javase/9/migrate/toc.htm • Modular Development with JDK 9 • https://www.youtube.com/watch?v=gtcTftvj0d0 • Modules in One Lesson by Mark Reinhold • https://www.youtube.com/watch?v=rFhhLXcOBsk • Project Jigsaw in JDK 9: Modularity ComesTo Java - Simon Ritter • https://www.youtube.com/watch?v=Ks7J_qQVR7Y 58
  • 59. ¡MUCHAS GRACIAS POR SU ATENCIÓN! 59
  • 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.