Support
Quality
Security
License
Reuse
kandi has reviewed picocli and discovered the below as its top functions. This is intended to give you an instant insight into picocli implemented functionality, and help decide if they suit your requirements.
Picocli is a modern framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It supports colors, autocompletion, subcommands, and more. In 1 source file so apps can include as source & avoid adding a dependency. Written in Java, usable from Groovy, Kotlin, Scala, etc.
Help to promote picocli
[](https://github.com/remkop/picocli)
Example
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
@Command(name = "example", mixinStandardHelpOptions = true, version = "Picocli example 4.0")
public class Example implements Runnable {
@Option(names = { "-v", "--verbose" },
description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
private boolean[] verbose = new boolean[0];
@Parameters(arity = "1..*", paramLabel = "FILE", description = "File(s) to process.")
private File[] inputFiles;
public void run() {
if (verbose.length > 0) {
System.out.println(inputFiles.length + " files to process...");
}
if (verbose.length > 1) {
for (File f : inputFiles) {
System.out.println(f.getAbsolutePath());
}
}
}
public static void main(String[] args) {
// By implementing Runnable or Callable, parsing, error handling and handling user
// requests for usage help or version help can be done with one line of code.
int exitCode = new CommandLine(new Example()).execute(args);
System.exit(exitCode);
}
}
Gradle
implementation 'info.picocli:picocli:4.6.3'
Maven
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.6.3</version>
</dependency>
Scala SBT
libraryDependencies += "info.picocli" % "picocli" % "4.6.3"
Ivy
<dependency org="info.picocli" name="picocli" rev="4.6.3" />
Grape
@Grapes(
@Grab(group='info.picocli', module='picocli', version='4.6.3')
)
Leiningen
[info.picocli/picocli "4.6.3"]
Buildr
'info.picocli:picocli:jar:4.6.3'
JBang
//DEPS info.picocli:picocli:4.6.3
How can I construct the help functionality to divide subcommands into groups with separate descriptive headers?
@Command(name = "help", helpCommand = true)
class Help implements Runnable {
public static Map<String, String[]> commandGroups;
static {
commandGroups = new HashMap<>();
commandGroups.put("group1", new String[]{
"function1", "function2", "function3"});
commandGroups.put("group2", new String[]{
"function3", "function4", "function5"});
}
@Override
public void run() {
CommandLine cmd = new CommandLine(new Tool());
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST_HEADING);
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST);
List<String> keys = new ArrayList<>(cmd.getHelpSectionKeys());
for (String group : commandGroups.keySet()) {
String headerSection = "SECTION_KEY_" + group + "_HEADING";
String commandSection = "SECTION_KEY_" + group;
cmd.getHelpSectionMap().put(headerSection,
help -> help.createHeading("%n" + group + ":%n"));
cmd.getHelpSectionMap().put(commandSection,
new CommandListRenderer(commandGroups.get(group)));
keys.add(headerSection);
keys.add(commandSection);
}
cmd.setHelpSectionKeys(keys);
cmd.usage(System.out);
}
}
class CommandListRenderer implements IHelpSectionRenderer {
String[] functions;
public CommandListRenderer(String[] f) {
functions = f;
}
//@Override
public String render(Help help) {
CommandSpec spec = help.commandSpec();
if (spec.subcommands().isEmpty()) { return ""; }
// prepare layout: two columns
// the left column overflows, the right column wraps if text is too long
Help.TextTable textTable =
Help.TextTable.forColumns(help.colorScheme(),
new Help.Column(30, 2, Help.Column.Overflow.SPAN),
new Help.Column(spec.usageMessage().width() - 30, 2,
Help.Column.Overflow.TRUNCATE));
for (String f : functions) {
CommandLine subcommand = spec.subcommands().get(f);
if (subcommand == null) {
throw new NotFoundException("Function not found: " + f);
}
addCommand(subcommand, textTable);
}
return textTable.toString();
}
public void addCommand(CommandLine cmd, Help.TextTable textTable) {
// create comma-separated list of command name and aliases
String names = cmd.getCommandSpec().names().toString();
names = names.substring(1, names.length() - 1); // remove leading '[' and trailing ']'
// command description is taken from header or description
String description = description(cmd.getCommandSpec().usageMessage());
// add a line for this command to the layout
textTable.addRowValues(names, description);
}
private String description(Model.UsageMessageSpec usageMessage) {
if (usageMessage.header().length > 0) {
return usageMessage.header()[0];
}
if (usageMessage.description().length > 0) {
return usageMessage.description()[0];
}
return "";
}
Micronaut application built with Launch4J not launching
task createExe(type: Launch4jLibraryTask) {
jarTask = shadowJar
dontWrapJar true // <<<< THIS IS THE ADDED LINE
icon = "${projectDir}/src/main/installer/nsis/Icon.ico"
outfile = "${appName}.exe"
copyConfigurable = files {}
stayAlive = 'true'
bundledJrePath = 'jre'
bundledJre64Bit = true
jvmOptions = [
'-Xmx1024m',
'-Dsun.java2d.d3d=false'
]
fileDescription = appName + ' Application'
productName = appName
internalName = appName
copyright = 'My Company'
companyName = 'My Company'
}
arggroup with default value in picocli
@Command
public class CMD implements Runnable {
@Parameters
private String x;
@ArgGroup(exclusive = false)
private Group group = new Group();
static class Group {
@Option(names = "-a", required = true, defaultValue = "aa")
public static String a = "aa";
@Option(names = "-b", required = true, defaultValue = "bb")
public static String b = "bb";
@Option(names = "-c", required = false, defaultValue = "cc")
public static String c = "cc";
}
@Command
static class CMD implements Runnable {
@Parameters
private String x;
@ArgGroup(exclusive = false)
private Group group = new Group();
static class Group {
@ArgGroup(exclusive = false)
private InnerGroup inner = new InnerGroup("aa", "bb"); // default values
@Option(names = "-c", required = false, defaultValue = "cc")
public String c = "cc";
}
static class InnerGroup {
// default constructor, used by picocli when
// one or more options in this group are
// matched on the command line
public InnerGroup() {}
// this constructor assigns default values,
// used only when *both* options are missing
public InnerGroup(String a, String b) {
this.a = a;
this.b = b;
}
@Option(names = "-a", required = true)
public String a;
@Option(names = "-b", required = true)
public String b;
}
@Override
public void run() {
System.out.printf("a=%s, b=%s, c=%s, x=%s%n",
group.inner.a, group.inner.b, group.c, x);
}
}
-----------------------
@Command
public class CMD implements Runnable {
@Parameters
private String x;
@ArgGroup(exclusive = false)
private Group group = new Group();
static class Group {
@Option(names = "-a", required = true, defaultValue = "aa")
public static String a = "aa";
@Option(names = "-b", required = true, defaultValue = "bb")
public static String b = "bb";
@Option(names = "-c", required = false, defaultValue = "cc")
public static String c = "cc";
}
@Command
static class CMD implements Runnable {
@Parameters
private String x;
@ArgGroup(exclusive = false)
private Group group = new Group();
static class Group {
@ArgGroup(exclusive = false)
private InnerGroup inner = new InnerGroup("aa", "bb"); // default values
@Option(names = "-c", required = false, defaultValue = "cc")
public String c = "cc";
}
static class InnerGroup {
// default constructor, used by picocli when
// one or more options in this group are
// matched on the command line
public InnerGroup() {}
// this constructor assigns default values,
// used only when *both* options are missing
public InnerGroup(String a, String b) {
this.a = a;
this.b = b;
}
@Option(names = "-a", required = true)
public String a;
@Option(names = "-b", required = true)
public String b;
}
@Override
public void run() {
System.out.printf("a=%s, b=%s, c=%s, x=%s%n",
group.inner.a, group.inner.b, group.c, x);
}
}
In picocli how do you make options on the command line to override the same option in an @-file
import picocli.CommandLine.PropertiesDefaultProvider;
@Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
class MyApp {
@Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
myapp --sourceDatabaseType=MySQL -@.\myapp.options
class MyApp {
@Spec CommandSpec spec; // injected by picocli
@Option(names = "-@")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}
-----------------------
import picocli.CommandLine.PropertiesDefaultProvider;
@Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
class MyApp {
@Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
myapp --sourceDatabaseType=MySQL -@.\myapp.options
class MyApp {
@Spec CommandSpec spec; // injected by picocli
@Option(names = "-@")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}
-----------------------
import picocli.CommandLine.PropertiesDefaultProvider;
@Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
class MyApp {
@Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
myapp --sourceDatabaseType=MySQL -@.\myapp.options
class MyApp {
@Spec CommandSpec spec; // injected by picocli
@Option(names = "-@")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}
-----------------------
import picocli.CommandLine.PropertiesDefaultProvider;
@Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
class MyApp {
@Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
myapp --sourceDatabaseType=MySQL -@.\myapp.options
class MyApp {
@Spec CommandSpec spec; // injected by picocli
@Option(names = "-@")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}
-----------------------
import picocli.CommandLine.PropertiesDefaultProvider;
@Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
class MyApp {
@Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
myapp --sourceDatabaseType=MySQL -@.\myapp.options
class MyApp {
@Spec CommandSpec spec; // injected by picocli
@Option(names = "-@")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}
Bridging CLI argument parsing with application setup
@Command(subcommands = {Sub1.class, Sub2.class, Sub3.class})
class MyApp implements Runnable {
Channel channel; // initialized in executionStrategy method
// A reference to this method can be used as a custom execution strategy
// that first calls the init() method,
// and then delegates to the default execution strategy.
private int executionStrategy(ParseResult parseResult) {
// custom initialization to be done before executing any command or subcommand
try (this.channel = _establishChannel(generalConfiguration)) {
// default execution strategy
return new CommandLine.RunLast().execute(parseResult);
}
}
public static void main(String[] args) {
MyApp app = new MyApp();
new CommandLine(app)
// wire in the custom execution strategy
.setExecutionStrategy(app::executionStrategy) // Java 8 method reference syntax
.execute(args);
}
// ...
}
@Command(name = "country", description = "Resolve ISO country code (ISO-3166-1, Alpha-2 code)")
static class Subcommand1 implements Runnable {
@ParentCommand
private MyApp parent; // picocli injects reference to parent command
@Parameters(arity = "1..*", paramLabel = "<country code>", description = "country code(s) to be resolved")
private String[] countryCodes;
@Override
public void run() {
Channel channel = parent.channel;
doSomethingWith(channel);
// ...
}
}
-----------------------
@Command(subcommands = {Sub1.class, Sub2.class, Sub3.class})
class MyApp implements Runnable {
Channel channel; // initialized in executionStrategy method
// A reference to this method can be used as a custom execution strategy
// that first calls the init() method,
// and then delegates to the default execution strategy.
private int executionStrategy(ParseResult parseResult) {
// custom initialization to be done before executing any command or subcommand
try (this.channel = _establishChannel(generalConfiguration)) {
// default execution strategy
return new CommandLine.RunLast().execute(parseResult);
}
}
public static void main(String[] args) {
MyApp app = new MyApp();
new CommandLine(app)
// wire in the custom execution strategy
.setExecutionStrategy(app::executionStrategy) // Java 8 method reference syntax
.execute(args);
}
// ...
}
@Command(name = "country", description = "Resolve ISO country code (ISO-3166-1, Alpha-2 code)")
static class Subcommand1 implements Runnable {
@ParentCommand
private MyApp parent; // picocli injects reference to parent command
@Parameters(arity = "1..*", paramLabel = "<country code>", description = "country code(s) to be resolved")
private String[] countryCodes;
@Override
public void run() {
Channel channel = parent.channel;
doSomethingWith(channel);
// ...
}
}
How to decide Quarkus application arguments in Kubernetes at run-time?
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3
ARG JAVA_PACKAGE=java-11-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 1001
# [== BEFORE ==]
# ENTRYPOINT [ "/deployments/run-java.sh" ]
# [== AFTER ==]
ENTRYPOINT "/deployments/run-java.sh" $CLI_ARGUMENTS
How do I transfer my parsed array data from one class to another?
class getArrayElements extends SourceSentences {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
SourceSentences.translate();
System.out.println(SourceSentences.sourceArray);
}
}
Should EntityManagerFactory be closed at application shutdown?
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
@Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
@Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
@Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
@Override
public void closeDbConnection() {
client.close();
}
}
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}
-----------------------
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
@Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
@Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
@Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
@Override
public void closeDbConnection() {
client.close();
}
}
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}
-----------------------
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
@Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
@Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
@Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
@Override
public void closeDbConnection() {
client.close();
}
}
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}
-----------------------
public interface DBInitializer {
public void startDbConnection();
public void closeDbConnection();
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class MySQLInitializer implements DBInitializer {
private EntityManagerFactory emf;
private EntityManager entityManager;
private final Logger logger = LogManager.getLogger(MySQLInitializer.class);
@Override
public void startDbConnection() {
try {
emf = Persistence.createEntityManagerFactory("name");
entityManager = emf.createEntityManager();
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "MySQL Exception", e);
}
}
@Override
public void closeDbConnection() {
if (emf != null) {
entityManager.close();
emf.close();
}
}
}
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
public class MongoInitializer implements DBInitializer {
private MongoClient client;
private final Logger logger = LogManager.getLogger(MongoInitializer.class);
@Override
public void startDbConnection() {
try {
client = new MongoClient(new ServerAddress("localhost", 27017));
// other stuff
} catch (Exception e) {
logger.log(Level.ERROR, "Mongo Exception", e);
}
}
@Override
public void closeDbConnection() {
client.close();
}
}
import java.awt.EventQueue;
import java.util.concurrent.Callable;
import DBInitializer;
import MongoInitializer;
import MySQLInitializer;
import View;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(mixinStandardHelpOptions = true)
public class App implements Callable<Void> {
private static final Logger LOGGER = LogManager.getLogger(App.class);
@Option(names = { "--database" }, description = "Either 'mongo' or 'mysql'")
private String databaseType = "mysql";
public static void main(String[] args) {
new CommandLine(new App()).execute(args);
}
DBInitializer dBInitializer;
@Override
public Void call() throws Exception {
EventQueue.invokeLater(() -> {
try {
switch (databaseType) {
case "mysql":
dBInitializer = new MySQLInitializer();
break;
case "mongo":
dBInitializer = new MongoInitializer();
break;
default:
LOGGER.log(Level.ERROR, "--database must be either 'mysql' or 'mongo'");
System.exit(1);
}
dBInitializer.startDbConnection();
// other stuff
View view = new View();
view.setVisible(true);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Exception", e);
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
dBInitializer.closeDbConnection();
}
});
return null;
}
}
Groovy 4, JDK 11: Caught: Assertion failed
-Dgroovy.attach.runtime.groovydoc=true
@Option with enum List does not accept candidates that ${COMPLETION-CANDIDATES} shows
public class HeaderConverter implements CommandLine.ITypeConverter<List<Header>> {
@Override
public List<Header> convert(String s) throws Exception {
List<Header> headers = new ArrayList<>();
var params = s.split(",");
Arrays.stream(params).forEach(x -> headers.add(Header.valueOf(x.trim())));
return headers;
}
}
QUESTION
How can I construct the help functionality to divide subcommands into groups with separate descriptive headers?
Asked 2022-Apr-08 at 12:48A tool I am currently working on has a lot of subcommands which makes picocli's help output unclear. My code looks like this:
@Command(name = "toolName",
version = "version",
sortOptions = false,
parameterListHeading = "%nParameters:%n",
optionListHeading = "%nOptions:%n",
commandListHeading = "%nThese are common commands:%n%n",
subcommands = {
command1.class,
command2.class,
command3.class,
etc.class }
With help as:
@Option(names = {"-h", "--help"}, scope = ScopeType.INHERIT, usageHelp = true,
description = "Display this help message.")
boolean usageHelpRequested;
I want the help output to look similar to git's:
Here subcommands are divided into different functionalities (like start a working area) with a description. Is this possible using picocli?
ANSWER
Answered 2022-Apr-08 at 02:49Yes that is possible by diving under the hood of picocli's Help API.
One idea is to have a custom IHelpSectionRenderer
, see this example: https://github.com/remkop/picocli/blob/main/picocli-examples/src/main/java/picocli/examples/customhelp/GroupingDemo.java
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
No vulnerabilities reported
Save this library and start creating your kit
Save this library and start creating your kit