Analisi dei parametri della riga di comando con la compagnia aerea

1. Introduzione

In questo tutorial, introdurremo Airline, una libreria Java basata su annotazioni per la creazione di interfacce della riga di comando (CLI).

2. Scenario

Quando si crea un'applicazione a riga di comando, è naturale creare un'interfaccia semplice per consentire all'utente di modellare l'output secondo necessità. Quasi tutti hanno giocato con Git CLI e possono capire quanto sia potente, ma semplice. Purtroppo, pochi strumenti sono utili quando si crea un'interfaccia del genere.

La compagnia aerea mira a ridurre il codice boilerplate tipicamente associato ai CLI in Java , poiché i comportamenti più comuni possono essere ottenuti con annotazioni e zero codice utente.

Implementeremo un piccolo programma Java che sfrutterà le funzionalità di Airline per imitare una CLI comune. Esporrà i comandi dell'utente per impostare la configurazione del nostro programma, come la definizione dell'URL del database, delle credenziali e del livello di dettaglio del logger. Ci immergeremo anche sotto la superficie della nostra libreria e useremo più delle sue basi per sondare se può gestire una certa complessità.

3. Configurazione

Per iniziare, aggiungiamo la dipendenza della compagnia aerea al nostro pom.xm l:

 com.github.rvesse airline 2.7.2  

4. Una semplice CLI

Creiamo il nostro punto di ingresso per l'applicazione: la classe CommandLine :

@Cli(name = "baeldung-cli", description = "Baeldung Airline Tutorial", defaultCommand = Help.class) public class CommandLine { public static void main(String[] args) { Cli cli = new Cli(CommandLine.class); Runnable cmd = cli.parse(args); cmd.run(); } }

Attraverso una semplice annotazione @Cli , abbiamo definito il comando predefinito che verrà eseguito sulla nostra applicazione: il comando Help .

La classe Help fa parte della libreria Airline ed espone un comando di guida predefinito utilizzando le opzioni -h o –help .

Proprio così, la configurazione di base è completata.

5. Il nostro primo comando

Implementiamo il nostro primo comando, una semplice classe LoggingCommand che controllerà la verbosità dei nostri log. Annoteremo la classe con @Command per assicurarci che venga applicato il comando corretto quando l'utente chiama setup-log :

@Command(name = "setup-log", description = "Setup our log") public class LoggingCommand implements Runnable { @Inject private HelpOption help; @Option(name = { "-v", "--verbose" }, description = "Set log verbosity on/off") private boolean verbose = false; @Override public void run() { if (!help.showHelpIfRequested()) System.out.println("Verbosity: " + verbose); } } }

Diamo un'occhiata più da vicino al nostro comando di esempio.

Innanzitutto, abbiamo impostato una descrizione in modo che il nostro helper, grazie all'iniezione, visualizzi le nostre opzioni di comando quando richiesto.

Quindi abbiamo dichiarato una variabile booleana , dettagliata e annotata con @Option per darle un nome, una descrizione e anche un alias -v / –verbose per rappresentare la nostra opzione della riga di comando per controllare la verbosità.

Infine, all'interno del metodo run , abbiamo ordinato al nostro comando di fermarsi ogni volta che l'utente chiede aiuto.

Fin qui tutto bene. Ora, dobbiamo aggiungere il nostro nuovo comando all'interfaccia principale modificando l' annotazione @ Cli :

@Cli(name = "baeldung-cli", description = "Baeldung Airline Tutorial", defaultCommand = Help.class, commands = { LoggingCommand.class, Help.class }) public class CommandLine { public static void main(String[] args) { Cli cli = new Cli(CommandLine.class); Runnable cmd = cli.parse(args); cmd.run(); } } 

Ora, se passiamo setup-log -v al nostro programma, eseguirà la nostra logica.

6. Vincoli e altro

Abbiamo visto come Airline genera la CLI in modo impeccabile, ma ... c'è di più!

Possiamo specificare vincoli (o restrizioni) per i nostri parametri per gestire valori, requisiti o dipendenze consentiti e altro ancora.

Creeremo una classe DatabaseSetupCommand , che risponderà al comando setup-db ; come abbiamo fatto prima, ma aggiungeremo un po 'di pepe.

Innanzitutto, richiederemo il tipo di database, accettando solo 3 valori validi tramite @AllowedRawValues :

@AllowedRawValues(allowedValues = { "mysql", "postgresql", "mongodb" }) @Option(type = OptionType.COMMAND, name = {"-d", "--database"}, description = "Type of RDBMS.", title = "RDBMS type: mysql|postgresql|mongodb") protected String rdbmsMode;

Quando si utilizza una connessione al database, senza alcun dubbio, gli utenti dovrebbero fornire un endpoint e alcune credenziali per accedervi. Consentiremo alla CLI di gestirlo tramite uno ( modalità URL) o più parametri ( modalità host ). Per questo, useremo l' annotazione @MutuallyExclusiveWith , contrassegnando ogni parametro con lo stesso tag:

@Option(type = OptionType.COMMAND, name = {"--rdbms:url", "--url"}, description = "URL to use for connection to RDBMS.", title = "RDBMS URL") @MutuallyExclusiveWith(tag="mode") @Pattern(pattern="^(//.*):(d*)(.*)u=(.*)&p=(.*)") protected String rdbmsUrl = ""; @Option(type = OptionType.COMMAND, name = {"--rdbms:host", "--host"}, description = "Host to use for connection to RDBMS.", title = "RDBMS host") @MutuallyExclusiveWith(tag="mode") protected String rdbmsHost = ""; 

Nota che abbiamo usato il decoratore @Pattern , che ci aiuta a definire il formato della stringa dell'URL.

Se esaminiamo la documentazione del progetto, troveremo altri preziosi strumenti per la gestione di requisiti, occorrenze, valori consentiti, casi specifici e altro, consentendoci di definire le nostre regole personalizzate .

Infine, se l'utente ha selezionato la modalità host, dovremmo chiedergli di fornire le proprie credenziali. In questo modo, un'opzione dipende da un'altra. Possiamo ottenere questo comportamento con l' annotazione @RequiredOnlyIf :

@RequiredOnlyIf(names={"--rdbms:host", "--host"}) @Option(type = OptionType.COMMAND, name = {"--rdbms:user", "-u", "--user"}, description = "User for login to RDBMS.", title = "RDBMS user") protected String rdbmsUser; @RequiredOnlyIf(names={"--rdbms:host", "--host"}) @Option(type = OptionType.COMMAND, name = {"--rdbms:password", "--password"}, description = "Password for login to RDBMS.", title = "RDBMS password") protected String rdbmsPassword; 

E se avessimo bisogno di utilizzare alcuni driver per gestire la connessione DB? Inoltre, supponiamo di dover ricevere più di un valore in un singolo parametro. Possiamo semplicemente cambiare il tipo di opzione in OptionType.ARGUMENTS o, ancora meglio, accettare un elenco di valori:

@Option(type = OptionType.COMMAND, name = {"--driver", "--jars"}, description = "List of drivers", title = "--driver  --driver ") protected List jars = new ArrayList();

Ora, non dimentichiamoci di aggiungere il comando di configurazione del database alla nostra classe principale. In caso contrario, non sarà disponibile sulla CLI.

7. Esegui

Ce l'abbiamo fatta! Abbiamo terminato il nostro progetto e ora possiamo eseguirlo.

Come previsto, senza passare alcun parametro, viene richiamata la Guida :

$ baeldung-cli usage: baeldung-cli  [  ] Commands are: help Display help information setup-db Setup our database setup-log Setup our log See 'baeldung-cli help ' for more information on a specific command.

Se invece eseguiamo setup-log –help , otteniamo:

$ baeldung-cli setup-log --help NAME baeldung-cli setup-log - Setup our log SYNOPSIS baeldung-cli setup-log [ -h  ] [ -v  ] OPTIONS -h, --help Display help information -v, --verbose Set log verbosity on/off

Infine, fornire parametri a questi comandi eseguirà la logica di business corretta.

8. Conclusione

In questo articolo abbiamo creato un'interfaccia a riga di comando semplice ma potente con pochissima codifica.

La libreria Airline, con le sue potenti funzionalità, semplifica la CLI, fornendoci un'infrastruttura generale, pulita e riutilizzabile . Consente a noi sviluppatori di concentrarci sulla nostra logica di business piuttosto che dedicare tempo alla progettazione di ciò che dovrebbe essere banale.

Come sempre, il codice può essere trovato su GitHub.