Related
I'm trying to understand a comment that a colleague made. We're using testcontainers to create a fixture:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
public class SalesforceFixture extends GenericContainer<SalesforceFixture> {
private static final String APPLICATION_NAME = "salesforce-emulator";
public SalesforceFixture() {
// super(ImageResolver.resolve(APPLICATION_NAME));
super(DockerImageName.parse("gcr.io/ad-selfserve/salesforce-emulator:latest"));
...
}
...
The commented code is what it used to be. The next line is my colleague's suggestion. And on that line he commented:
This is the part I don't know. The [ImageResolver] gets the specific version of the emulator, rather than the latest. You need a docker-info file for that though, which jib doesn't automatically generate (but I think it can).
This is what I know or have figured so far:
SalesforceFixture is a class that will be used by other projects to write tests. It spins up a container in Docker, running a service that emulates the real service's API. It's like a local version of the service that behaves enough like the real thing that if one writes code and tests using the fixture, it should work the same in production. (This is where my knowledge ends.)
I looked into ImageResolver—it seems to be a class we wrote that searches a filesystem for something:
public static String resolve(String applicationName, File... roots) {
Stream<File> searchPaths = Arrays.stream(roots).flatMap((value) -> {
return Stream.of(new File(value, "../" + applicationName), new File(value, applicationName));
});
Optional<File> buildFile = searchPaths.flatMap((searchFile) -> {
if (searchFile.exists()) {
File imageFile = new File(searchFile + File.separator + "/target/docker/image-name");
if (imageFile.exists()) {
return Stream.of(imageFile);
}
}
return Stream.empty();
}).findAny();
InputStream build = (InputStream)buildFile.map(ImageResolver::fileStream).orElseGet(() -> {
return searchClasspath(applicationName);
});
if (build != null) {
try {
return IOUtils.toString(build, Charset.defaultCharset()).trim();
} catch (IOException var6) {
throw new RuntimeException("An exception has occurred while reading build file", var6);
}
} else {
throw new RuntimeException("Could not resolve target image for application: " + applicationName);
}
}
But I'm confused. What filesystem? Like, what is the present working directory? My local computer, wherever I ran the Java program from? Or is this from within some container? (I don't think so.) Or maybe the directory structure inside a .jar file? Or somewhere in gcr.io?
What does he mean about a "specific version number" vs. "latest"? I mean, when I build this project, whatever it built is all I have. Isn't that equivalent to "latest"? In what case would an older version of an image be present? (That's what made me think of gcr.io.)
Or, does he mean, that in the project using this project's image, one will not be able to specify a version via Maven/pom.xml—it will always spin up the latest.
Sorry this is long, just trying to "show my work." Any hints welcome. I'll keep looking.
I can't comment on specifics of your own internal implementations, but ImageResolver seems to work on your local filesystem, e.g. it looks into your target/ directory and also touches the classpath. I can imagine this code was just written for resolving an actual image name (not an image), since it also returns a String.
Regarding latest, using a latest tag for a Docker image is generally considered an anti-pattern, so likely your colleague is commenting about this. Here is a random article from the web explaining some of the issues with latest tag:
https://vsupalov.com/docker-latest-tag/
Besides, I don't understand why you ask these questions which are very specific to your project here on SO rather than asking your colleague.
What is a good way of parsing command line arguments in Java?
Check these out:
http://commons.apache.org/cli/
http://www.martiansoftware.com/jsap/
Or roll your own:
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
For instance, this is how you use commons-cli to parse 2 string arguments:
import org.apache.commons.cli.*;
public class Main {
public static void main(String[] args) throws Exception {
Options options = new Options();
Option input = new Option("i", "input", true, "input file path");
input.setRequired(true);
options.addOption(input);
Option output = new Option("o", "output", true, "output file");
output.setRequired(true);
options.addOption(output);
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
CommandLine cmd = null;//not a good practice, it serves it purpose
try {
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
formatter.printHelp("utility-name", options);
System.exit(1);
}
String inputFilePath = cmd.getOptionValue("input");
String outputFilePath = cmd.getOptionValue("output");
System.out.println(inputFilePath);
System.out.println(outputFilePath);
}
}
usage from command line:
$> java -jar target/my-utility.jar -i asd
Missing required option: o
usage: utility-name
-i,--input <arg> input file path
-o,--output <arg> output file
Take a look at the more recent JCommander.
I created it. I’m happy to receive questions or feature requests.
I have been trying to maintain a list of Java CLI parsers.
Airline
Active Fork: https://github.com/rvesse/airline
argparse4j
argparser
args4j
clajr
cli-parser
CmdLn
Commandline
DocOpt.java
dolphin getopt
DPML CLI (Jakarta Commons CLI2 fork)
Dr. Matthias Laux
Jakarta Commons CLI
jargo
jargp
jargs
java-getopt
jbock
JCLAP
jcmdline
jcommander
jcommando
jewelcli (written by me)
JOpt simple
jsap
naturalcli
Object Mentor CLI article (more about refactoring and TDD)
parse-cmd
ritopt
Rop
TE-Code Command
picocli has ANSI colorized usage help and autocomplete
It is 2022, time to do better than Commons CLI... :-)
Should you build your own Java command line parser, or use a library?
Many small utility-like applications probably roll their own command line parsing to avoid the additional external dependency. picocli may be an interesting alternative.
Picocli is a modern library and framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It lives in 1 source file so apps can include it as source to avoid adding a dependency.
It supports colors, autocompletion, subcommands, and more. Written in Java, usable from Groovy, Kotlin, Scala, etc.
Features:
Annotation based: declarative, avoids duplication and expresses programmer intent
Convenient: parse user input and run your business logic with one line of code
Strongly typed everything - command line options as well as positional parameters
POSIX clustered short options (<command> -xvfInputFile as well as <command> -x -v -f InputFile)
Fine-grained control: an arity model that allows a minimum, maximum and variable number of parameters, e.g, "1..*", "3..5"
Subcommands (can be nested to arbitrary depth)
Feature-rich: composable arg groups, splitting quoted args, repeatable subcommands, and many more
User-friendly: usage help message uses colors to contrast important elements like option names from the rest of the usage help to reduce the cognitive load on the user
Distribute your app as a GraalVM native image
Works with Java 5 and higher
Extensive and meticulous documentation
The usage help message is easy to customize with annotations (without programming). For example:
(source)
I couldn't resist adding one more screenshot to show what usage help messages are possible. Usage help is the face of your application, so be creative and have fun!
Disclaimer: I created picocli. Feedback or questions very welcome.
Someone pointed me to args4j lately which is annotation based. I really like it!
I've used JOpt and found it quite handy: http://jopt-simple.sourceforge.net/
The front page also provides a list of about 8 alternative libraries, check them out and pick the one that most suits your needs.
I know most people here are going to find 10 million reasons why they dislike my way, but nevermind. I like to keep things simple, so I just separate the key from the value using a '=' and store them in a HashMap like this:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split("=");
argsMap.put(parts[0], parts[1]);
}
You could always maintain a list with the arguments you are expecting, to help the user in case he forgot an argument or used a wrong one... However, if you want too many features this solution is not for you anyway.
This is Google's command line parsing library open-sourced as part of the Bazel project. Personally I think it's the best one out there, and far easier than Apache CLI.
https://github.com/pcj/google-options
Installation
Bazel
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)
Gradle
dependencies {
compile 'com.github.pcj:google-options:1.0.0'
}
Maven
<dependency>
<groupId>com.github.pcj</groupId>
<artifactId>google-options</artifactId>
<version>1.0.0</version>
</dependency>
Usage
Create a class that extends OptionsBase and defines your #Option(s).
package example;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
import java.util.List;
/**
* Command-line options definition for example server.
*/
public class ServerOptions extends OptionsBase {
#Option(
name = "help",
abbrev = 'h',
help = "Prints usage info.",
defaultValue = "true"
)
public boolean help;
#Option(
name = "host",
abbrev = 'o',
help = "The server host.",
category = "startup",
defaultValue = ""
)
public String host;
#Option(
name = "port",
abbrev = 'p',
help = "The server port.",
category = "startup",
defaultValue = "8080"
)
public int port;
#Option(
name = "dir",
abbrev = 'd',
help = "Name of directory to serve static files.",
category = "startup",
allowMultiple = true,
defaultValue = ""
)
public List<String> dirs;
}
Parse the arguments and use them.
package example;
import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;
public class Server {
public static void main(String[] args) {
OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
parser.parseAndExitUponError(args);
ServerOptions options = parser.getOptions(ServerOptions.class);
if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
printUsage(parser);
return;
}
System.out.format("Starting server at %s:%d...\n", options.host, options.port);
for (String dirname : options.dirs) {
System.out.format("\\--> Serving static files at <%s>\n", dirname);
}
}
private static void printUsage(OptionsParser parser) {
System.out.println("Usage: java -jar server.jar OPTIONS");
System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
OptionsParser.HelpVerbosity.LONG));
}
}
https://github.com/pcj/google-options
Take a look at the Commons CLI project, lots of good stuff in there.
Yeap.
I think you're looking for something like this:
http://commons.apache.org/cli
The Apache Commons CLI library provides an API for processing command line interfaces.
If you are already using Spring Boot, argument parsing comes out of the box.
If you want to run something after startup, implement the ApplicationRunner interface:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(ApplicationArguments args) {
args.containsOption("my-flag-option"); // test if --my-flag-option was set
args.getOptionValues("my-option"); // returns values of --my-option=value1 --my-option=value2
args.getOptionNames(); // returns a list of all available options
// do something with your args
}
}
Your run method will be invoked after the context has started up successfully.
If you need access to the arguments before you fire up your application context, you can just simply parse the application arguments manually:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
ApplicationArguments arguments = new DefaultApplicationArguments(args);
// do whatever you like with your arguments
// see above ...
SpringApplication.run(Application.class, args);
}
}
And finally, if you need access to your arguments in a bean, just inject the ApplicationArguments:
#Component
public class MyBean {
#Autowired
private ApplicationArguments arguments;
// ...
}
Maybe these
JArgs command line option parsing
suite for Java - this tiny project provides a convenient, compact, pre-packaged and comprehensively documented suite of command line option parsers for the use of Java programmers. Initially, parsing compatible with GNU-style 'getopt' is provided.
ritopt, The Ultimate Options Parser for Java - Although, several command line option standards have been preposed, ritopt follows the conventions prescribed in the opt package.
I wrote another one: http://argparse4j.sourceforge.net/
Argparse4j is a command line argument parser library for Java, based on Python's argparse.
If you are familiar with gnu getopt, there is a Java port at: http://www.urbanophile.com/arenn/hacking/download.htm.
There appears to be a some classes that do this:
http://docs.sun.com/source/816-5618-10/netscape/ldap/util/GetOpt.html
http://xml.apache.org/xalan-j/apidocs/org/apache/xalan/xsltc/cmdline/getopt/GetOpt.html
airline # Github looks good. It is based on annotation and is trying to emulate Git command line structures.
Argparse4j is best I have found. It mimics Python's argparse libary which is very convenient and powerful.
I want to show you my implementation: ReadyCLI
Advantages:
for lazy programmers: a very small number of classes to learn, just see the two small examples on the README in the repository and you are already at 90% of learning; just start coding your CLI/Parser without any other knowledge;
ReadyCLI allows coding CLIs in the most natural way;
it is designed with Developer Experience in mind; it largely uses the Builder design pattern and functional interfaces for Lambda Expressions, to allow a very quick coding;
it supports Options, Flags and Sub-Commands;
it allows to parse arguments from command-line and to build more complex and interactive CLIs;
a CLI can be started on Standard I/O just as easily as on any other I/O interface, such as sockets;
it gives great support for documentation of commands.
I developed this project as I needed new features (options, flag, sub-commands) and that could be used in the simplest possible way in my projects.
If you want something lightweight (jar size ~ 20 kb) and simple to use, you can try argument-parser. It can be used in most of the use cases, supports specifying arrays in the argument and has no dependency on any other library. It works for Java 1.5 or above. Below excerpt shows an example on how to use it:
public static void main(String[] args) {
String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
InputData inputData = (InputData) argParser.parse(args);
showData(inputData);
new StatsGenerator().generateStats(inputData);
}
More examples can be found here
As one of the comments mentioned earlier (https://github.com/pcj/google-options) would be a good choice to start with.
One thing I want to add-on is:
1) If you run into some parser reflection error, please try use a newer version of the guava. in my case:
maven_jar(
name = "com_google_guava_guava",
artifact = "com.google.guava:guava:19.0",
server = "maven2_server",
)
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
server = "maven2_server",
)
maven_server(
name = "maven2_server",
url = "http://central.maven.org/maven2/",
)
2) When running the commandline:
bazel run path/to/your:project -- --var1 something --var2 something -v something
3) When you need the usage help, just type:
bazel run path/to/your:project -- --help
Take a look at Spring Shell
Spring Shell’s features include
A simple, annotation driven, programming model to contribute custom commands
Use of Spring Boot auto-configuration functionality as the basis for a command plugin strategy
Tab completion, colorization, and script execution
Customization of command prompt, shell history file name, handling of results and errors
Dynamic enablement of commands based on domain specific criteria
Integration with the bean validation API
Already built-in commands, such as clear screen, gorgeous help, exit
ASCII art Tables, with formatting, alignment, fancy borders, etc.
For Spring users, we should mention also https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html and his twin brother https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html (JOpt implementation of the same functionality).
The advantage in Spring is that you can directly bind the command line arguments to attributes, there is an example here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/CommandLinePropertySource.html
What is a good way of parsing command line arguments in Java?
Check these out:
http://commons.apache.org/cli/
http://www.martiansoftware.com/jsap/
Or roll your own:
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
For instance, this is how you use commons-cli to parse 2 string arguments:
import org.apache.commons.cli.*;
public class Main {
public static void main(String[] args) throws Exception {
Options options = new Options();
Option input = new Option("i", "input", true, "input file path");
input.setRequired(true);
options.addOption(input);
Option output = new Option("o", "output", true, "output file");
output.setRequired(true);
options.addOption(output);
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
CommandLine cmd = null;//not a good practice, it serves it purpose
try {
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
formatter.printHelp("utility-name", options);
System.exit(1);
}
String inputFilePath = cmd.getOptionValue("input");
String outputFilePath = cmd.getOptionValue("output");
System.out.println(inputFilePath);
System.out.println(outputFilePath);
}
}
usage from command line:
$> java -jar target/my-utility.jar -i asd
Missing required option: o
usage: utility-name
-i,--input <arg> input file path
-o,--output <arg> output file
Take a look at the more recent JCommander.
I created it. I’m happy to receive questions or feature requests.
I have been trying to maintain a list of Java CLI parsers.
Airline
Active Fork: https://github.com/rvesse/airline
argparse4j
argparser
args4j
clajr
cli-parser
CmdLn
Commandline
DocOpt.java
dolphin getopt
DPML CLI (Jakarta Commons CLI2 fork)
Dr. Matthias Laux
Jakarta Commons CLI
jargo
jargp
jargs
java-getopt
jbock
JCLAP
jcmdline
jcommander
jcommando
jewelcli (written by me)
JOpt simple
jsap
naturalcli
Object Mentor CLI article (more about refactoring and TDD)
parse-cmd
ritopt
Rop
TE-Code Command
picocli has ANSI colorized usage help and autocomplete
It is 2022, time to do better than Commons CLI... :-)
Should you build your own Java command line parser, or use a library?
Many small utility-like applications probably roll their own command line parsing to avoid the additional external dependency. picocli may be an interesting alternative.
Picocli is a modern library and framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It lives in 1 source file so apps can include it as source to avoid adding a dependency.
It supports colors, autocompletion, subcommands, and more. Written in Java, usable from Groovy, Kotlin, Scala, etc.
Features:
Annotation based: declarative, avoids duplication and expresses programmer intent
Convenient: parse user input and run your business logic with one line of code
Strongly typed everything - command line options as well as positional parameters
POSIX clustered short options (<command> -xvfInputFile as well as <command> -x -v -f InputFile)
Fine-grained control: an arity model that allows a minimum, maximum and variable number of parameters, e.g, "1..*", "3..5"
Subcommands (can be nested to arbitrary depth)
Feature-rich: composable arg groups, splitting quoted args, repeatable subcommands, and many more
User-friendly: usage help message uses colors to contrast important elements like option names from the rest of the usage help to reduce the cognitive load on the user
Distribute your app as a GraalVM native image
Works with Java 5 and higher
Extensive and meticulous documentation
The usage help message is easy to customize with annotations (without programming). For example:
(source)
I couldn't resist adding one more screenshot to show what usage help messages are possible. Usage help is the face of your application, so be creative and have fun!
Disclaimer: I created picocli. Feedback or questions very welcome.
Someone pointed me to args4j lately which is annotation based. I really like it!
I've used JOpt and found it quite handy: http://jopt-simple.sourceforge.net/
The front page also provides a list of about 8 alternative libraries, check them out and pick the one that most suits your needs.
I know most people here are going to find 10 million reasons why they dislike my way, but nevermind. I like to keep things simple, so I just separate the key from the value using a '=' and store them in a HashMap like this:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split("=");
argsMap.put(parts[0], parts[1]);
}
You could always maintain a list with the arguments you are expecting, to help the user in case he forgot an argument or used a wrong one... However, if you want too many features this solution is not for you anyway.
This is Google's command line parsing library open-sourced as part of the Bazel project. Personally I think it's the best one out there, and far easier than Apache CLI.
https://github.com/pcj/google-options
Installation
Bazel
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)
Gradle
dependencies {
compile 'com.github.pcj:google-options:1.0.0'
}
Maven
<dependency>
<groupId>com.github.pcj</groupId>
<artifactId>google-options</artifactId>
<version>1.0.0</version>
</dependency>
Usage
Create a class that extends OptionsBase and defines your #Option(s).
package example;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
import java.util.List;
/**
* Command-line options definition for example server.
*/
public class ServerOptions extends OptionsBase {
#Option(
name = "help",
abbrev = 'h',
help = "Prints usage info.",
defaultValue = "true"
)
public boolean help;
#Option(
name = "host",
abbrev = 'o',
help = "The server host.",
category = "startup",
defaultValue = ""
)
public String host;
#Option(
name = "port",
abbrev = 'p',
help = "The server port.",
category = "startup",
defaultValue = "8080"
)
public int port;
#Option(
name = "dir",
abbrev = 'd',
help = "Name of directory to serve static files.",
category = "startup",
allowMultiple = true,
defaultValue = ""
)
public List<String> dirs;
}
Parse the arguments and use them.
package example;
import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;
public class Server {
public static void main(String[] args) {
OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
parser.parseAndExitUponError(args);
ServerOptions options = parser.getOptions(ServerOptions.class);
if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
printUsage(parser);
return;
}
System.out.format("Starting server at %s:%d...\n", options.host, options.port);
for (String dirname : options.dirs) {
System.out.format("\\--> Serving static files at <%s>\n", dirname);
}
}
private static void printUsage(OptionsParser parser) {
System.out.println("Usage: java -jar server.jar OPTIONS");
System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
OptionsParser.HelpVerbosity.LONG));
}
}
https://github.com/pcj/google-options
Take a look at the Commons CLI project, lots of good stuff in there.
Yeap.
I think you're looking for something like this:
http://commons.apache.org/cli
The Apache Commons CLI library provides an API for processing command line interfaces.
If you are already using Spring Boot, argument parsing comes out of the box.
If you want to run something after startup, implement the ApplicationRunner interface:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(ApplicationArguments args) {
args.containsOption("my-flag-option"); // test if --my-flag-option was set
args.getOptionValues("my-option"); // returns values of --my-option=value1 --my-option=value2
args.getOptionNames(); // returns a list of all available options
// do something with your args
}
}
Your run method will be invoked after the context has started up successfully.
If you need access to the arguments before you fire up your application context, you can just simply parse the application arguments manually:
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
ApplicationArguments arguments = new DefaultApplicationArguments(args);
// do whatever you like with your arguments
// see above ...
SpringApplication.run(Application.class, args);
}
}
And finally, if you need access to your arguments in a bean, just inject the ApplicationArguments:
#Component
public class MyBean {
#Autowired
private ApplicationArguments arguments;
// ...
}
Maybe these
JArgs command line option parsing
suite for Java - this tiny project provides a convenient, compact, pre-packaged and comprehensively documented suite of command line option parsers for the use of Java programmers. Initially, parsing compatible with GNU-style 'getopt' is provided.
ritopt, The Ultimate Options Parser for Java - Although, several command line option standards have been preposed, ritopt follows the conventions prescribed in the opt package.
I wrote another one: http://argparse4j.sourceforge.net/
Argparse4j is a command line argument parser library for Java, based on Python's argparse.
If you are familiar with gnu getopt, there is a Java port at: http://www.urbanophile.com/arenn/hacking/download.htm.
There appears to be a some classes that do this:
http://docs.sun.com/source/816-5618-10/netscape/ldap/util/GetOpt.html
http://xml.apache.org/xalan-j/apidocs/org/apache/xalan/xsltc/cmdline/getopt/GetOpt.html
airline # Github looks good. It is based on annotation and is trying to emulate Git command line structures.
Argparse4j is best I have found. It mimics Python's argparse libary which is very convenient and powerful.
I want to show you my implementation: ReadyCLI
Advantages:
for lazy programmers: a very small number of classes to learn, just see the two small examples on the README in the repository and you are already at 90% of learning; just start coding your CLI/Parser without any other knowledge;
ReadyCLI allows coding CLIs in the most natural way;
it is designed with Developer Experience in mind; it largely uses the Builder design pattern and functional interfaces for Lambda Expressions, to allow a very quick coding;
it supports Options, Flags and Sub-Commands;
it allows to parse arguments from command-line and to build more complex and interactive CLIs;
a CLI can be started on Standard I/O just as easily as on any other I/O interface, such as sockets;
it gives great support for documentation of commands.
I developed this project as I needed new features (options, flag, sub-commands) and that could be used in the simplest possible way in my projects.
If you want something lightweight (jar size ~ 20 kb) and simple to use, you can try argument-parser. It can be used in most of the use cases, supports specifying arrays in the argument and has no dependency on any other library. It works for Java 1.5 or above. Below excerpt shows an example on how to use it:
public static void main(String[] args) {
String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
InputData inputData = (InputData) argParser.parse(args);
showData(inputData);
new StatsGenerator().generateStats(inputData);
}
More examples can be found here
As one of the comments mentioned earlier (https://github.com/pcj/google-options) would be a good choice to start with.
One thing I want to add-on is:
1) If you run into some parser reflection error, please try use a newer version of the guava. in my case:
maven_jar(
name = "com_google_guava_guava",
artifact = "com.google.guava:guava:19.0",
server = "maven2_server",
)
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
server = "maven2_server",
)
maven_server(
name = "maven2_server",
url = "http://central.maven.org/maven2/",
)
2) When running the commandline:
bazel run path/to/your:project -- --var1 something --var2 something -v something
3) When you need the usage help, just type:
bazel run path/to/your:project -- --help
Take a look at Spring Shell
Spring Shell’s features include
A simple, annotation driven, programming model to contribute custom commands
Use of Spring Boot auto-configuration functionality as the basis for a command plugin strategy
Tab completion, colorization, and script execution
Customization of command prompt, shell history file name, handling of results and errors
Dynamic enablement of commands based on domain specific criteria
Integration with the bean validation API
Already built-in commands, such as clear screen, gorgeous help, exit
ASCII art Tables, with formatting, alignment, fancy borders, etc.
For Spring users, we should mention also https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html and his twin brother https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html (JOpt implementation of the same functionality).
The advantage in Spring is that you can directly bind the command line arguments to attributes, there is an example here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/CommandLinePropertySource.html
I got a little project where I have to compute a list. The computation depends on serveal factors.
The point is that these factors change from time to time and the user should be allowed to change this by it's self.
Up to now, the factors are hard-coded and no changes can be done without recompiling the code.
At the moment the code looks like this:
if (someStatement.equals("someString")) {
computedList.remove("something");
}
My idea is to make an editable and human readable textfile, configfile, etc. which is loaded at runtime/ at startup? This file should hold the java code from above.
Any ideas how to do that? Please note: The targeted PCs do not have the JDK installed, only an JRE.
An effective way of going about this is using a static initializer. Static Block in Java A good and concise explanation can be found under this link.
One option here that would allow this would be to use User Input Dialogs from the swing API - then you could store the users answer's in variables and export them to a text file/config file, or just use them right in the program without saving them. You would just have the input dialogs pop up at the very beginning of the program before anything else happens, and then the program would run based off those responses.
You could use Javascript for the configuration file language, instead of java. Java 7 SE and later includes a javascript interpreter that you can call from Java. it's not difficult to use, and you can inject java objects into the javascript environment.
Basically, you'd create a Javascript environment, insert the java objects into it which the config file is expected to configure, and then run the config file as javascript.
Okay, here we go... I found an quite simple solution for my problem.
I am using Janino by Codehaus (Link). This library has an integrated Java compiler and seems to work like the JavaCompiler class in Java 7.
BUT without having the JDK to be installed.
Through Janino you can load and compile *.java files(which are human readable) at runtime, which was exactly what I needed.
I think the examples and code-snippets on their homepage are just painful, so here's my own implementation:
Step one is to implement an interface with the same methods your Java file has which is loaded at runtime:
public interface ZuordnungInterface {
public ArrayList<String> Zuordnung(ArrayList<String> rawList);}
Then you call the Janino classloader when you need the class:
File janinoSourceDir = new File(PATH_TO_JAVAFILE);
File[] srcDir = new File[] { janinoSourceDir };
String encoding = null;
ClassLoader parentClassLoader = this.getClass().getClassLoader();
ClassLoader cl = new JavaSourceClassLoader(parentClassLoader, srcDir,
encoding);
And create an new instance
ZuordnungsInterface myZuordnung = (ZuordnungInterface) cl.loadClass("zuordnung")
.newInstance();
Note: The class which is loaded is named zuordnung.java, so there is no extension needed in the call cl.loadClass("zuordnung").
And finaly the class I want to load and compile at runtime of my program, which can be located wherever you want it to be (PATH_TO_JAVAFILE):
public class zuordnung implements ZuordnungInterface {
public ArrayList<String> Zuordnung(ArrayList<String> rawList){
ArrayList<String> computedList = (ArrayList<String>) rawList.clone();
if (Model.getSomeString().equals("Some other string")) {
computedList.add("Yeah, I loaded an external Java class");
}
return computedList;
}}
That's it. Hope it helps others with similar problems!
OK, again having some problems with caliper.
I am now running on Linux, trying to use the beta snapshot. I am attempting to run Google's caliper via commandline using just the jar. (Beta snapshot)
I do not have access to maven on this machine, and installing it is out of the question. I would just like to use a jar and, maybe once this is working, I can write up a script or something.
Here is what I am doing:
1. Using small example Benchmark:
import com.google.caliper.Benchmark;
public class Tutorial {
public static class Benchmark1 {
#Benchmark void timeNanoTime(int reps) {
for (int i = 0; i < reps; i++) {
System.nanoTime();
}
}
}
}
2. Compile with javac -cp caliper-1.0-beta-SNAPSHOT-all.jar Tutorial.java
3. (Attempt to) run with
java -cp caliper-1.0-beta-SNAPSHOT-all.jar com.google.caliper.runner.CaliperMain Tutorial.Benchmark1, receive message Benchmark class not found: Tutorial.Benchmark1.
I've tried to work this out from bits and pieces of information from various sources but I am really having a heck of a time with this. I would appreciate any input.
I believe you really need no maven, this should work.
Your own class doesn't get found and I think it's a problem of your classpath. As they're usually more problem with nested classes try simply
java -cp caliper-1.0-beta-SNAPSHOT-all.jar com.google.caliper.runner.CaliperMain Tutorial
If the message changes to something like "class contains no benchmarks", then you'll know more. If you insists on using nested class, you may need to call Tutorial$Benchmark1 (unprobable, but possible; java class naming is sick).
Please try also
java -cp caliper-1.0-beta-SNAPSHOT-all.jar Tutorial.Benchmark1
to see if your class lies on the classpath (the message should change to something like "no main method").
See also this older post.