Vytvorte program príkazového riadku Java s programom Picocli

1. Úvod

V tomto výučbe si priblížime picocli knižnica, ktorá nám umožňuje ľahko vytvárať programy príkazového riadku v Jave.

Najprv začneme vytvorením príkazu Hello World. Potom sa hlboko ponoríme do hlavných funkcií knižnice tým, že čiastočne reprodukujeme git príkaz.

2. Ahoj svetové velenie

Začnime niečím ľahkým: príkazom Hello World!

Najskôr je potrebné pridať závislosť do picocli projekt:

 info.picocli picocli 3.9.6 

Ako vidíme, použijeme 3.9.6 verzia knižnice, aj keď a 4.0.0 verzia je vo výstavbe (momentálne k dispozícii v alfa teste).

Teraz, keď je závislosť nastavená, vytvorme náš príkaz Hello World. Za týmto účelom použijeme @ Príkaz anotácia z knižnice:

@Command (name = "ahoj", description = "pozdravuje") verejná trieda HelloWorldCommand {}

Ako vidíme, anotácia môže mať parametre. Používame tu iba dva z nich. Ich účelom je poskytnúť informácie o aktuálnom príkaze a texte pre automatickú správu pomoci.

Momentálne s týmto príkazom nemôžeme veľa urobiť. Aby sme niečo dokázali, musíme pridať a hlavný volanie metódy pohodlie CommandLine.run (spustiteľný, reťazec []) metóda. Toto vyžaduje dva parametre: inštanciu nášho príkazu, ktorý musí implementovať Spustiteľné rozhranie a String pole predstavujúce argumenty príkazu (možnosti, parametre a čiastkové príkazy):

verejná trieda HelloWorldCommand implementuje Runnable {public static void main (String [] args) {CommandLine.run (new HelloWorldCommand (), args); } @Override public void run () {System.out.println ("Hello World!"); }}

Teraz, keď spustíme hlavný metódou, uvidíme, že výstupy konzoly "Ahoj svet!"

Keď sme zabalení do pohára, môžeme spustiť náš príkaz Hello World pomocou java príkaz:

java -cp "pathToPicocliJar; pathToCommandJar" com.baeldung.picoli.helloworld.HelloWorldCommand

Niet divu, že tiež výstupy "Ahoj svet!" strunu do konzoly.

3. Konkrétny prípad použitia

Teraz, keď sme videli základné informácie, sa ponoríme do hĺbky picocli knižnica. Aby sme to dosiahli, čiastočne zreprodukujeme populárny príkaz: git.

Účelom samozrejme nebude implementácia git príkazové správanie, ale na reprodukciu možností git príkaz - ktoré podpríkazy existujú a aké možnosti sú k dispozícii pre zvláštny podpríkaz.

Najskôr musíme vytvoriť a GitCommand triedy, ako sme to urobili pre náš príkaz Hello World:

@Command verejná trieda GitCommand implementuje Runnable {public static void main (String [] args) {CommandLine.run (nový GitCommand (), args); } @Override public void run () {System.out.println ("Populárny príkaz git"); }}

4. Pridávanie čiastkových príkazov

The git príkaz ponúka veľa čiastkových príkazov - pridať, potvrdiť, vzdialený, a mnoho ďalších. Tu sa ešte zameriame pridať a spáchať.

Našim cieľom teda bude deklarovať tieto dva čiastkové príkazy hlavnému príkazu. Picocli ponúka tri spôsoby, ako to dosiahnuť.

4.1. Pomocou @ Príkaz Anotácia k triedam

The @ Príkaz anotácia ponúka možnosť registrácie čiastkových príkazov cez internet čiastkové príkazy parameter:

@Command (subcommands = {GitAddCommand.class, GitCommitCommand.class})

V našom prípade pridáme dve nové triedy: GitAddCommand a GitCommitCommand. Obe sú anotované výrazom @ Príkaz a realizovať Spustiteľné. Je dôležité dať im meno, pretože mená budú používané picocli rozpoznať, ktoré čiastkové príkazy sa majú vykonať:

@Command (name = "add") verejná trieda GitAddCommand implementuje Runnable {@Override public void run () {System.out.println ("Pridanie niektorých súborov do pracovnej oblasti"); }}
@Command (name = "commit") verejná trieda GitCommitCommand implementuje Runnable {@Override public void run () {System.out.println ("Spáchanie súborov v pracovnej oblasti, aké úžasné?"); }}

Ak teda spustíme náš hlavný príkaz pomocou pridať ako argument sa zobrazí konzola „Pridávanie niektorých súborov do pracovnej oblasti“.

4.2. Pomocou @ Príkaz Anotácia k metódam

Ďalším spôsobom, ako deklarovať čiastkové príkazy, je vytvoriť @ Príkaz- anotované metódy predstavujúce tieto príkazy v GitCommand trieda:

@Command (name = "add") public void addCommand () {System.out.println ("Pridanie niektorých súborov do pracovnej oblasti"); } @Command (name = "commit") public void commitCommand () {System.out.println ("Spúšťanie súborov v pracovnej oblasti, aké úžasné?"); }

Takto môžeme priamo implementovať našu obchodnú logiku do metód a nevytvárať samostatné triedy, ktoré by to zvládali.

4.3. Programové pridávanie čiastkových príkazov

Nakoniec picocli nám ponúka možnosť programovo registrovať naše čiastkové príkazy. Je to trochu zložitejšie, pretože musíme vytvoriť Príkazový riadok objekt zalomí náš príkaz a potom k nemu pridá čiastkové príkazy:

CommandLine commandLine = nový CommandLine (nový GitCommand ()); commandLine.addSubcommand ("pridať", nový GitAddCommand ()); commandLine.addSubcommand ("commit", nový GitCommitCommand ());

Potom musíme ešte spustiť príkaz, ale nemôžeme využiť CommandLine.run () metóda už nie. Teraz musíme zavolať parseWithHandler () metóda na našom novo vytvorenom CommandLine objekt:

commandLine.parseWithHandler (nový RunLast (), args);

Mali by sme vziať na vedomie použitie RunLast trieda, ktorá hovorí picocli spustiť najkonkrétnejší čiastkový príkaz. Existujú ďalšie dva ovládače príkazov, ktoré poskytuje picocli: RunFirst a RunAll. Prvý spúšťa najvyšší príkaz, zatiaľ čo druhý spúšťa všetky.

Pri použití pohodlnej metódy CommandLine.run (), RunLast v predvolenom nastavení sa používa obslužná rutina.

5. Správa možností pomocou @Možnosť Anotácia

5.1. Možnosť bez argumentu

Pozrime sa teraz, ako pridať niektoré možnosti do našich príkazov. Naozaj by sme chceli povedať svoje pridať príkaz, že má pridať všetky upravené súbory. Aby ste to dosiahli, pridáme pole s poznámkou @Možnosť anotácia k nášmu GitAddCommand trieda:

@Option (names = {"-A", "--all"}) private boolean allFiles; @Override public void run () {if (allFiles) {System.out.println ("Pridanie všetkých súborov do pracovnej oblasti"); } else {System.out.println ("Pridanie niektorých súborov do pracovnej oblasti"); }}

Ako vidíme, anotácia trvá a mien parameter, ktorý dáva rôzne názvy možnosti. Preto volanie na pridať príkaz buď -A alebo –Všetky nastaví všetky súbory pole do pravda. Pokiaľ teda spustíme príkaz s možnosťou, konzola sa zobrazí „Pridávanie všetkých súborov do pracovnej oblasti“.

5.2. Možnosť s argumentom

Ako sme práve videli, pre možnosti bez argumentov sa ich prítomnosť alebo neprítomnosť vždy hodnotí na a boolovský hodnotu.

Je však možné zaregistrovať možnosti, ktoré berú argumenty. Môžeme to urobiť jednoducho vyhlásením nášho poľa za iný typ. Pridajme a správa možnosť k nášmu spáchať príkaz:

@Option (names = {"-m", "--message"}) súkromná reťazcová správa; @Override public void run () {System.out.println ("Spúšťanie súborov v pracovnej oblasti, aké úžasné?"); if (message! = null) {System.out.println ("Správa o potvrdení je" + správa); }}

Nie je prekvapením, že keď je dané správa Táto možnosť zobrazí príkaz na konzole. Ďalej v článku sa budeme zaoberať tým, ktoré typy spracováva knižnica a ako zaobchádzať s inými typmi.

5.3. Možnosť s viacerými argumentmi

Ale teraz, čo keď chceme, aby náš príkaz prijímal viac správ, ako je to v skutočnosti git spáchať velenie? Žiaden strach, urobme z nášho poľa pole alebo a Zbierka, a sme dosť hotoví:

@Option (names = {"-m", "--message"}) súkromné ​​správy []; @Override public void run () {System.out.println ("Spúšťanie súborov v pracovnej oblasti, aké úžasné?"); if (messages! = null) {System.out.println ("Správa o potvrdení je"); pre (String message: messages) {System.out.println (správa); }}}

Teraz môžeme použiť správa možnosť viackrát:

potvrdiť -m "Moje potvrdenie je skvelé" -m "Moje potvrdenie je krásne"

Možno by sme však chceli dať možnosť iba raz a oddeliť rôzne parametre oddeľovačom regulárneho výrazu. Preto môžeme použiť rozdeliť parameter parametra @Možnosť anotácia:

@Option (names = {"-m", "--message"}, split = ",") súkromné ​​správy [];

Teraz môžeme prejsť -m „Môj záväzok je skvelý“, „Môj záväzok je krásny“ dosiahnuť rovnaký výsledok ako vyššie.

5.4. Požadovaná možnosť

Niekedy môžeme mať požadovanú možnosť. The požadovaný argument, ktorý je predvolene nastavený na nepravdivé, umožňuje nám to:

@ Voľba (names = {"-m", "--message"}, required = true) súkromné ​​správy [];

Teraz je nemožné zavolať spáchať príkaz bez zadania správa možnosť. Ak sa o to pokúsime, picocli vytlačí chybu:

Chýba požadovaná možnosť '--message =' Použitie: git commit -m = [-m =] ... -m, --message =

6. Správa pozičných parametrov

6.1. Zachyťte pozičné parametre

Teraz sa zamerajme na naše pridať príkaz, pretože to ešte nie je veľmi silné. Môžeme sa rozhodnúť iba pridať všetky súbory, ale čo keby sme chceli pridať konkrétne súbory?

Mohli by sme na to použiť inú možnosť, ale lepšou voľbou by tu bolo použitie pozičných parametrov. Naozaj, pozičné parametre sú určené na zachytenie argumentov príkazov, ktoré zaberajú konkrétne pozície a nie sú ani čiastkovými príkazmi, ani voľbami.

V našom príklade by nám to umožnilo robiť niečo ako:

pridať súbor1 súbor2

Na zachytenie pozičných parametrov využijeme @Parametre anotácia:

@Parameters súkromné ​​súbory zoznamu; @Override public void run () {if (allFiles) {System.out.println ("Pridanie všetkých súborov do pracovnej oblasti"); } if (súbory! = null) {files.forEach (cesta -> System.out.println ("Pridanie" + cesta + "do pracovnej oblasti")); }}

Teraz by náš príkaz z predchádzajúcej verzie vytlačil:

Pridanie súboru1 do pracovnej oblasti Pridanie súboru2 do pracovnej oblasti

6.2. Zachyťte podmnožinu polohových parametrov

Vďaka tomu je možné dosiahnuť jemnejšie podrobnosti o tom, ktoré pozičné parametre sa majú zachytiť index parameter anotácie. Index je založený na nule. Ak teda definujeme:

@Parameters (index = "2 .. *")

To by zachytilo argumenty, ktoré sa nezhodujú s možnosťami alebo čiastkovými príkazmi, od tretieho po koniec.

Index môže byť buď rozsah, alebo jedno číslo predstavujúce jednu pozíciu.

7. Slovo o prepočte typov

Ako sme už videli v tomto tutoriále, picocli niektoré konverzie typov zvláda sám. Napríklad mapuje viac hodnôt na polia alebo Zbierky, ale môže tiež mapovať argumenty na konkrétne typy, ako keď použijeme Cesta trieda pre pridať príkaz.

V skutočnosti picocli prichádza s hromadou vopred spracovaných typov. To znamená, že tieto typy môžeme použiť priamo bez toho, aby sme museli premýšľať o ich prevedení sami.

Možno však budeme musieť namapovať naše argumenty príkazov na iné typy, ako sú tie, ktoré sú už spracované. Našťastie pre nás, je to možné vďaka ITypeConverter rozhranie a CommandLine # registerConverter metóda, ktorá spája typ s prevodníkom.

Poďme si predstaviť, že chceme pridať konfigur čiastkový príkaz k nášmu git príkaz, ale nechceme, aby používatelia zmenili konfiguračný prvok, ktorý neexistuje. Takže sa rozhodneme tieto prvky namapovať na enum:

public enum ConfigElement {USERNAME ("user.name"), EMAIL ("user.email"); súkromná konečná hodnota reťazca; ConfigElement (hodnota reťazca) {this.value = hodnota; } public String value () {návratová hodnota; } public static ConfigElement from (String value) {return Arrays.stream (values ​​()) .filter (element -> element.value.equals (value)) .findFirst () .orElseThrow (() -> new IllegalArgumentException ("The argument "+ hodnota +" sa nezhoduje so žiadnym parametrom ConfigElement ")); }}

Navyše v našej novovytvorenej GitConfigCommand triedy, pridajme dva pozičné parametre:

@Parameters (index = "0") súkromný prvok ConfigElement; @Parameters (index = "1") súkromná hodnota reťazca; @Override public void run () {System.out.println ("Nastavenie" + element.value () + "na" + hodnotu); }

Týmto spôsobom zabezpečíme, že používatelia nebudú môcť meniť neexistujúce konfiguračné prvky.

Nakoniec musíme náš prevodník zaregistrovať. Krásne je, že ak používame Java 8 alebo vyššiu, nemusíme ani vytvárať triedu implementujúcu ITypeConverter rozhranie. Môžeme len odovzdať lambdu alebo odkaz na metódu k registerConverter () metóda:

CommandLine commandLine = nový CommandLine (nový GitCommand ()); commandLine.registerConverter (ConfigElement.class, ConfigElement :: from); commandLine.parseWithHandler (nový RunLast (), args);

To sa deje v GitCommand hlavný() metóda. Upozorňujeme, že sme museli pohodlie pustiť CommandLine.run () metóda.

Ak sa použije s nespracovaným konfiguračným prvkom, príkaz zobrazí pomocnú správu spolu s informáciami, ktoré nám hovoria, že nebolo možné previesť parameter na ConfigElement:

Neplatná hodnota pozičného parametra na indexe 0 (): nemožno konvertovať „user.phone“ na ConfigElement (java.lang.IllegalArgumentException: Argument user.phone sa nezhoduje so žiadnym ConfigElement) Použitie: git config 

8. Integrácia s Spring Boot

Na záver sa pozrime, ako to všetko vylepšiť!

V skutočnosti možno pracujeme v prostredí Spring Boot a chceme z toho ťažiť v našom programe príkazového riadku. Za týmto účelom musíme vytvoriť SpringBootApplicationimplementácia CommandLineRunner rozhranie:

@SpringBootApplication verejná trieda Aplikácia implementuje CommandLineRunner {public static void main (String [] args) {SpringApplication.run (Application.class, args); } @Override public void run (String ... args) {}}

Plus, poďme anotovať všetky naše príkazy a čiastkové príkazy pomocou pružiny @ Komponent anotácia a autowire to všetko v našom Aplikácia:

súkromný GitCommand gitCommand; súkromný GitAddCommand addCommand; súkromný GitCommitCommand commitCommand; súkromný GitConfigCommand configCommand; verejná aplikácia (GitCommand gitCommand, GitAddCommand addCommand, GitCommitCommand commitCommand, GitConfigCommand configCommand) {this.gitCommand = gitCommand; this.addCommand = addCommand; this.commitCommand = commitCommand; this.configCommand = configCommand; }

Upozorňujeme, že každý čiastkový príkaz sme museli autowire. Je to bohužiaľ preto, lebo nateraz picocli zatiaľ nie je schopný načítať čiastkové príkazy z jarného kontextu, keď je deklarovaný deklaratívne (s anotáciami). Preto si toto zapojenie budeme musieť urobiť sami, programovo:

@Override public void run (String ... args) {CommandLine commandLine = nový CommandLine (gitCommand); commandLine.addSubcommand ("add", addCommand); commandLine.addSubcommand ("commit", commitCommand); commandLine.addSubcommand ("config", configCommand); commandLine.parseWithHandler (nový CommandLine.RunLast (), args); }

A teraz náš program príkazového riadku funguje ako kúzlo s komponentami Spring. Preto by sme mohli vytvoriť niektoré triedy služieb a použiť ich v našich príkazoch a nechať Spring, aby sa postaral o vloženie závislosti.

9. Záver

V tomto článku sme videli niektoré kľúčové vlastnosti picocli knižnica. Naučili sme sa, ako vytvoriť nový príkaz a pridať k nemu niekoľko čiastkových príkazov. Už sme videli veľa spôsobov, ako sa vysporiadať s možnosťami a pozičnými parametrami. Navyše sme sa naučili, ako implementovať vlastné prevádzače typov, aby boli naše príkazy silne zadané. Konečne sme videli, ako vložiť Spring Boot do našich príkazov.

Existuje samozrejme veľa ďalších vecí, ktoré môžete objaviť. Knižnica poskytuje kompletnú dokumentáciu.

Celý kód tohto článku nájdete na našom serveri GitHub.


$config[zx-auto] not found$config[zx-overlay] not found