Lekce 3 - Vytvoření prvního modulu v Javě
V předchozí lekci, Classloader a první modul v Javě, jsme se dozvěděli, co je to classloader a jak funguje načítání tříd v Javě. Popsali jsme si různé typy modulů a ukázali jsme si, jak takový modul definujeme.
V dnešní lekci našeho Java tutoriálu si ukážeme, jak vytvořit moduly a jak funguje komunikace mezi nimi. Projekt bude řízen Mavenem. Cílem bude přepsat Zdraviče z OOP lekcí na zdraviče z modulů.
Struktura projektu
Budeme mít celkem tři moduly:
- hlavní - zde bude main metoda,
- api - zde bude jedno rozhraní definující metodu pro zdraviče,
- impl - implementace různých zdravičů.
Základní myšlenka tohoto návrhu je oddělení specifikace od implementace. V budoucnu můžeme například napsat další modul, ve kterém budeme chtít napsat další druh zdraviče. Můžeme to brát jako rozšíření stávající implementace.
Tvorba projektu
Začneme tvorbou nového projektu. Jak už bylo řečeno, projekt bude řízen Mavenem.
Protože budeme tvořit vlastní strukturu projektu, nepoužijeme žádný archetyp, který nám Maven nabízí. Zároveň budeme složky vytvářet mimo naše vývojové prostředí.
Nejdříve si založíme novou složku s projektem. Složku nazveme
cz.itnetwork.moduly
. Do ní přidáme tři podsložky:
cz.itnetwork.moduly.zdravic
,
cz.itnetwork.moduly.zdravic.api
,
cz.itnetwork.moduly.zdravic.impl
a soubor pom.xml
. V
každé podsložce také vytvoříme další soubor pom.xml
. Dále
do každé podsložky přidáme vnořené složky:
src/main/java/
.
Vznikne nám následující adresářová struktura:
cz.itnetwork.moduly |-cz.itnetwork.moduly.zdravic | |-src | | |-main | | | |-java | |-pom.xml |-cz.itnetwork.moduly.zdravic.api | |-src | | |-main | | | |-java | |-pom.xml |-cz.itnetwork.moduly.zdravic.impl | |-src | | |-main | | | |-java | |-pom.xml |-pom.xml
Maven konfigurace
Teď postupně vyplníme jednotlivé pom.xml
soubory. Hlavní
konfigurační pom.xml
soubor bude zatím obsahovat pouze
základní informace o projektu. Dále bude obsahovat seznam (maven)
submodulů:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cz.itnetwork.moduly</groupId> <artifactId>cz.itnetwork.moduly</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <name>cz.itnetwork.moduly</name> <properties> <!-- https://maven.apache.org/general.html#encoding-warning --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>18</maven.compiler.source> <maven.compiler.target>18</maven.compiler.target> </properties> <modules> <module>cz.itnetwork.moduly.zdravic</module> <module>cz.itnetwork.moduly.zdravic.api</module> <module>cz.itnetwork.moduly.zdravic.impl</module> </modules> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
Je velmi důležité, aby bylo přítomno nastavení maven
compiler pluginu. Zejména definice source
a target
.
Pokud toto nastavení vynecháme, budeme se později potýkat s problémy,
protože kompilátor nebude schopný najít Java modul!
Konfigurační soubory pom.xml
v submodulech budou všechny
zatím vypadat stejně. Lišit se budou pouze v názvu. Případné další
úpravy provedeme až budou potřeba:
<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cz.itnetwork.moduly</groupId> <artifactId>cz.itnetwork.moduly</artifactId> <version>1.0-SNAPSHOT</version> </parent> <version>1.0-SNAPSHOT</version> <artifactId>cz.itnetwork.moduly.zdravic</artifactId> <!-- na tomto řádku upravte artifactId dle modulu zdravic/zdravic.api/zdravic.impl --> <name>cz.itnetwork.moduly.zdravic</name> <!-- na tomto řádku upravte name dle modulu zdravic/zdravic.api/zdravic.impl --> </project>
Otevření projektu ve vývojovém prostředí
Když už máme založený projekt, otevřeme si vývojové prostředí a v něm si projekt naimportujeme dle zvyklostí daného IDE. V případě IntelliJ zvolíme otevřít existující projekt a vybereme kořenovou složku projektu. IntelliJ je dostatečně chytré, aby rozpoznalo, že se jedná o Maven projekt a synchronizuje si veškeré složky.
Definice rozhraní
Začneme v modulu zdravic.api
, který bude obsahovat jedno
rozhraní s jednou metodou definující způsob, jak se bude uživatel zdravit.
Nejdříve zde ve složce src/main/java/
založíme nový balíček
s názvem cz.itnetwork.moduly.zdravic.api
. V balíčku pak
založíme rozhraní IZdravic
s metodou pozdrav()
:
package cz.itnetwork.moduly.zdravic.api; public interface IZdravic { String pozdrav(String jmeno); }
Implementace rozhraní
Přesuneme se do modulu zdravic.impl
a opět vytvoříme nový
balíček, tentokrát s názvem cz.itnetwork.moduly.zdravic.impl
. V
balíčku založíme třídu ZdravicZakladni
, která bude
implementovat rozhraní IZdravic
:
package cz.itnetwork.moduly.zdravic.impl; import cz.itnetwork.moduly.zdravic.api.IZdravic; public class ZdravicZakladni implements IZdravic { private static final String FORMAT_POZDRAVU = "Ahoj uživateli %s"; @Override public String pozdrav(String jmeno) { return FORMAT_POZDRAVU.formatted(jmeno); } }
Importem balíčku cz.itnetwork.moduly.zdravic.impl
jsme
vytvořili přímou závislost. IntelliJ nás upozorní, že
tuto závislost musíme oznámit Mavenu. V modulu zdravic.impl
tedy
otevřeme konfigurační soubor pom.xml
, kam přidáme Maven
závislost:
<dependencies> <dependency> <groupId>cz.itnetwork.moduly</groupId> <artifactId>cz.itnetwork.moduly.zdravic.api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
Zadrátování
Nakonec přejdeme do posledního (hlavního) modulu a stejně jako v
předchozích modulech, i zde vytvoříme nový balíček s názvem
cz.itnetwork.moduly.zdravic
. V něm založíme novou třídu
pojmenovanou Aplikace
:
package cz.itnetwork.moduly.zdravic; import cz.itnetwork.moduly.zdravic.api.IZdravic; import cz.itnetwork.moduly.zdravic.impl.ZdravicZakladni; public class Aplikace { public static void main(String[] args) { IZdravic zdravicZakladni = new ZdravicZakladni(); System.out.println(zdravicZakladni.pozdrav("Karel")); } }
Aby nám zde fungovaly importy balíčků zdravic.api
a
zdravic.impl
, musíme opět upravit Maven konfiguraci v
pom.xml
souboru hlavního modulu a přidat do něj závislosti na
předchozích modulech:
<dependencies> <dependency> <groupId>cz.itnetwork.moduly</groupId> <artifactId>cz.itnetwork.moduly.zdravic.api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>cz.itnetwork.moduly</groupId> <artifactId>cz.itnetwork.moduly.zdravic.impl</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
Když teď zkompilujeme celý projekt a spustíme hlavní třídu, dostaneme následující výpis:
Konzolová aplikace
Ahoj uživateli Karel
Přidání Java modulů
Nyní přišel čas na přidání Java modulů. Z předchozí lekce již
víme, že moduly se zapisují do speciálním souboru
module-info.java
, který je umístěn v src
složce
daného modulu. V případě Mavenu se nachází ve složce
src/main/java/
.
Na následujících řádcích se bude často vyskytovat slovo modul. Někdy bude myšleno Maven modul a někdy zase Java modul. Typ bude vždy specifikován.
V Maven modulech cz.itnetwork.moduly.zdravic
,
cz.itnetwork.moduly.zdravic.api
a
cz.itnetwork.moduly.zdravic.impl
založíme nové Java moduly s
názvem odpovídajícím Maven modulu:
module cz.itnetwork.moduly.zdravic { } module cz.itnetwork.moduly.zdravic.api { } module cz.itnetwork.moduly.zdravic.impl { }
Když se teď pokusíme projekt zkompilovat, tak nám kompilace neprojde a skončí s chybou:
package cz.itnetwork.moduly.zdravic.api is not visible
Otevřeme si module-info
Java modulu
cz.itnetwork.moduly.zdravic.api
. Tento modul slouží primárně
jako veřejné API. To znamená, že chceme, aby mohl rozhraní použít
kdokoli. To zajistíme tím, že budeme exportovat daný
balíček. V našem případě se jedná o balíček
cz.itnetwork.moduly.zdravic.api
. Celá definice Java modulu bude
následující:
module cz.itnetwork.moduly.zdravic.api { exports cz.itnetwork.moduly.zdravic.api; }
Při pokusu o kompilaci bychom opět neuspěli a uviděli bychom navíc stále stejnou chybovou hlášku. Je to logické. Rozhraní jsme "otevřeli světu". Nyní musíme udělat druhý krok a říct, který modul toto rozhraní bude používat.
Otevřeme si module-info
Java modulu
cz.itnetwork.moduly.zdravic.impl
. Do modulu přidáme závislost na
modulu cz.itnetwork.moduly.zdravic.api
, zároveň
exportujeme balíček
cz.itnetwork.moduly.zdravic.impl
. Balíček opět musíme
exportovat, protože obsahuje konkrétní implementaci třídy, jejíž instanci
vytváříme ve třídě Aplikace
. Celá definice Java modulu bude
následující:
module cz.itnetwork.moduly.zdravic.impl { requires cz.itnetwork.moduly.zdravic.api; exports cz.itnetwork.moduly.zdravic.impl; }
Další pokus o kompilaci by vypsal chybovou hlášku, která se může zdát stejná, ale týká se jiného artefaktu:
package cz.itnetwork.moduly.zdravic.api is not visible package cz.itnetwork.moduly.zdravic.impl is not visible
Přesuneme se tedy ještě do module-info
hlavního Java modulu
a přidáme závislost na modul s rozhraním a modul s implementací. Celá
definice Java modulu bude následující:
module cz.itnetwork.moduly.zdravic { requires cz.itnetwork.moduly.zdravic.api; requires cz.itnetwork.moduly.zdravic.impl; }
Konečně se nám podaří projekt zkompilovat bez žádných chyb. Když teď aplikaci spustíme, dostaneme stejný výsledek, jako když jsme ji spouštěli bez modulů:
Konzolová aplikace
Ahoj uživateli Karel
Gratuluji, právě jsme společně modularizovali základní aplikaci.
V následujícím kvízu, Kvíz - Úvod, Classloader a Moduly, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 10x (10.09 kB)
Aplikace je včetně zdrojových kódů v jazyce Java