docs java java-9 java-module requires module-info

docs - ¿Cuál es la diferencia entre requiere y requiere declaraciones transitivas en Java 9?



documentation java 9 (6)

¿Cuál es la diferencia entre requiere y requiere declaraciones de módulo transitivo en la declaración del módulo?

Por ejemplo:

module foo { requires java.base; requires transitive java.compiler; }


Recapitulación de legibilidad

Si la barra de módulo requires módulo de bebida , entonces el sistema de módulo ...

  • impone la presencia de bebida (llamada configuración confiable )
  • permite que la barra lea la bebida (llamada readability )
  • permite código en barra para acceder a clases públicas en paquetes exportados en bebida (llamada accessibility )

Exactamente lo mismo sucede si la barra requires transitive drink : la bebida debe estar presente, puede leerse y acceder. De hecho, para bar and drink la palabra clave transitive no cambia nada.

Legibilidad implícita

Los módulos que dependen de la barra son los que se ven afectados por la transitive : cualquier módulo que lea la barra también puede leer la bebida . En otras palabras, la legibilidad de la bebida está implícita (por lo que esto se llama legibilidad implícita ). Una consecuencia es que el cliente puede acceder a los tipos de bebidas .

Por lo tanto, si la bar requires transitive drink y el customer requires bar , el cliente puede leer la bebida aunque no dependa explícitamente de ella.

Casos de uso

¿Pero por qué? Imagine que tiene un módulo cuya API pública acepta o devuelve el tipo de otro módulo. Digamos que el módulo de barras devuelve públicamente instancias de Drink , una interfaz del módulo de bebidas :

// in module _bar_ public class Bar { // `Drink` comes from the module _drink_, // which _bar_ requires public Drink buyDrink() { /* ... */ } }

En este ejemplo, la barra usa una bebida regular. Ahora diga, el cliente depende de la barra , por lo que todo su código puede llamar a Bar::buyDrink . ¿Pero qué pasa cuando lo hace?

El sistema de módulos se queja de que el cliente no lee bebidas y, por lo tanto, no puede acceder a Drink . Para solucionarlo, el cliente también tendría que depender de la bebida . ¡Qué tarea! ¿Qué tan inútil es una barra que no puedes usar de inmediato?

Por esta razón, se introdujo la legibilidad implícita: hacer que un módulo que utiliza los tipos de otro módulo en su propia API pública pueda utilizarse de forma instantánea sin que sea necesario que el que llama busque y requiera todos los módulos implicados.

Por lo tanto, si la bar requires transitive drink , el cliente puede comenzar a comprar bebidas sin tener que require drink , lo que require bar suficiente. Como debería.


El término accesibilidad es ambiguo: puede acceder a objetos sin acceso a su tipo. Si un objeto es de tipo T que se encuentra en un paquete que no se exporta y si un código "exportado" tiene un método que devuelve un T ... Entonces, al invocar este método, se maneja este objeto T (y se puede invoque en él cualquier método que pertenezca a cualquier tipo conocido en su código).

la legibilidad también es ambigua: no significa que su ClassLoader siempre será incapaz de cargar la clase T (no exportada).


La Especificación del lenguaje Java para Java 9 lo explica en términos muy simples. De la sección sobre Dependencias de Módulo :

La directiva requires especifica el nombre de un módulo del que el módulo actual tiene una dependencia.

...

La palabra clave requires puede ser seguida por el modificador transitive . Esto hace que cualquier módulo que requires que el módulo actual tenga una dependencia implícitamente declarada en el módulo especificado por la directiva requires transitive .

En otras palabras:

  • si el módulo X requires módulo Y,
  • y el módulo Y requires transitive módulo requires transitive Z,
  • entonces el módulo X también (implícitamente) requires módulo Z.

La diferencia principal entre los dos es el acceso de un módulo dependiente de uno a otro.

Si un módulo exporta un paquete que contiene un tipo cuya firma se refiere a un paquete en un segundo módulo, entonces la declaración del primer módulo debe incluir una dependencia requires transitive del segundo. Esto asegurará que otros módulos que dependen del primer módulo puedan leer automáticamente el segundo módulo y, por lo tanto, acceder a todos los tipos en los paquetes exportados de ese módulo.

Entonces, digamos para su caso de uso:

module foo { requires java.base; requires transitive java.compiler; }

~> Cualquier módulo que dependa del módulo foo leerá automáticamente el módulo java.compiler

~> Por otro lado, para acceder al módulo java.base , deben especificar una cláusula requires nuevamente.

module bar { requires foo; // java.compiler is available to read requires java.base; // still required }


Nicolai ha explicado en detalle. Solo estoy dando un ejemplo específico del código JDK aquí. Considere el módulo jdk.scripting.nashorn. El módulo-información de este módulo es el siguiente:

http://hg.openjdk.java.net/jdk9/dev/nashorn/file/17cc754c8936/src/jdk.scripting.nashorn/share/classes/module-info.java

Tiene esta línea:

requires transitive java.scripting;

Esto se debe a que la propia API del módulo jdk.scripting.nashorn en el paquete jdk.scripting.api.scripting acepta / devuelve tipos del paquete java.scripting módulo java.scripting . Entonces jdk.scripting.nashorn le dice al JMPS que cualquier módulo que dependa de jdk.scripting.nashorn también depende automáticamente del módulo java.scripting.

Ahora, el mismo módulo jdk.scripting.nashorn usa esta línea:

requires jdk.dynalink;

para otro módulo jdk.dynalink . Esto se debe a que ninguno de los paquetes exportados (la "API") del módulo jdk.scripting.nashorn usa tipos del módulo jdk.dynalink. El uso de jdk.dynalink por jdk.scripting.nashorn es puramente un detalle de implementación.


requires describir el proceso de resolución sobre cómo los módulos dependen el uno del otro.

Citando la línea

Una directiva ''requiere'' (independientemente de ''transitivo'') expresa que un módulo depende de otro módulo. El efecto del modificador "transitivo" es hacer que los módulos adicionales también dependan del otro módulo . Si el módulo M ''requiere N transitivo, entonces M no solo depende de N, sino que cualquier módulo que dependa de M también depende de N. Esto permite que M sea refactorizado para que parte o todo su contenido pueda moverse a un nuevo módulo N sin romper módulos que tienen una directiva ''requires M''.

En breve :

requires - M módulo depende de algún otro módulo N.

requires transitive : los módulos adicionales dependen implícitamente del otro módulo. Por ejemplo: si el módulo M depende de N, y el otro módulo P depende de M. Entonces, también depende implícitamente de N.