Related
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 am using LibSVM library on Weka 3.6 and experiencing similar problem as in here (for Java) and here (for Python)
The libSVM library generates a lot of logs simliar to this
optimization finished, #iter = 399
nu = 0.9503376170384973
obj = -124.54791151883072, rho = 0.0528133707297996
nSV = 257, nBSV = 97
I followed the solution using -q parameters by setting this parameter in my code:
LibSVM svm = new LibSVM();
String[] options = {"-q"};
svm.setOptions(options);
Although this solution seems to work in Python but I doesn't work in my Java code.
Another solution suggests using Log4j and disable some level of logs, however, I don't want to add another library to my code.
Now, I'm wondering is there any clean and simple solution to disable libSVM logs?
LibSVM library for Weka with FQN of "weka.classifiers.functions.LibSVM" is a wrapper around svm algorithm to create a common interface for Java programmers are using Weka API.
Inside "LibSVM.jar" there is another jar file which named "libsvm.jar" which is the main algorithm. Contrary to LibSVM which use common Java naming conventions, the naming convention inside "libsvm.jar" is different. Inside "libsvm" package there is a class named "svm". Because I had used "svm" as my variable name, the "svm" class was invisible.
After knowing that, I followed the instruction in here and changed the "svm" to "libsvm.svm" and this is the code which is working for me. In addition, I put this code in a static block of my code to have it for all my usages.
static{
libsvm.svm.svm_set_print_string_function(new libsvm.svm_print_interface() {
#Override
public void print(String s) {
} // Disables svm output
});
}
Finally, I am using LibSVM without annoying logs.
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 have written JNI wrappers to export the API of a C application (G-WAN) which embeds a JVM. The native calls are implemented in the C application and exported with RegisterNatives().
Ideally I would have a 'gwan' class for the G-WAN API:
import gwan // G-WAN API
public class hello {
public static int jmain(long env, String[] args) {
gwan.xbuf_cat(gwan.get_reply(env), "Hello World");
return 200; // HTTP status (200:'OK')
}
}
I would like to do something like the "#import gwan" above to import the native call prototypes, but currently I only have the following (which works):
public class hello {
public static int jmain(long env, String[] args) {
gwan_xbuf_cat(gwan_get_reply(env), "Hello World");
return 200; // HTTP status (200:'OK')
}
public static native long gwan_get_reply(long env);
public static native void gwan_xbuf_cat(long ctx, String str);
}
Again, the implementation of the native calls in made in the G-WAN executable (not in a Java class stored on disk).
Because the G-WAN API is quite large, I would like to have the native call prototypes in their own 'gwan' class (or namespace) if possible (like in the first hello example above).
Any suggestion about how to do that?
(please post Java or JNI code because I am not a Java expert)
Disclamer: I am involved in the development of this project.
I would suggest that you read following paper on JNI from Sun now Oracle
http://java.sun.com/docs/books/jni/html/jniTOC.html
And after that it should be understandable but some pseudocode and its not tested would be to move the two gwanapi calls into its own file named gwanapi.java
public class gwanapi {
public static native long get_reply(long answer);
public static native void xbuf_cat(long ctx,String str);
}
then you compile that file with javac gwanapi.java -> output: gwanapi.class
you type javah -jni for the c/c++ header implementation:
javah -jni gwanapi
the next you should in your hello java class is to call static{ System.loadLibrary("gwanapi");}
Pseudo code and NOT tested
public class hello{
static{
System.loadLibrary("gwanapi");
}
public static int jmain(long env,String args[]){
gwanapi.xbuf_cat(gwanapi.get_reply(env),"Hello World!");
return 200;
}
}
and you should be good to go.
But I might have missed a point or two but I think this is the smallest amount of work you should do.
Oh by the way http://en.wikipedia.org/wiki/Java_Native_Interface is also some form of source for JNI calls and how it works and lead you to more sites with more information.
Thanks
Being a C programmer, I have had to read the C source code of the JVM to find that Java remaps Class (path) names with dots instead of slashes.
Since the G-WAN directory hierarchy uses IP addresses to define listeners and virtual hosts (192.168.10.10_80/#domain.com/csp), those dots were confusing the FindClass() JNI call, making it fail to find the classes.
I also found that the classpath path separator is a ":" for Unix and a ";" for Windows. That was not the cause of my problem, but it might cause the same issue.
Finally, I stopped using the GCJ compiler's JVM because it does not support formating doubles (since at least 2006). Using either OpenJDK or the SUN/ORACLE JVM works as expected.
All works fine now. I post all this here just in case it may help others.
How do i call a Java command from a stand alone java program.
I understand that Runtime.getRuntime().exec("cmd c/ javac <>.java"); would work. However, this would be platform specific.
Any other APIs available that could make it work in j2sdk1.4 ?
If you can run everything in the same JVM, you could do something like this:
public class Launcher {
...
public static void main(String[] args) throws Exception {
launch(Class.forName(args[0]), programArgs(args, 1));
}
protected static void launch(Class program, String[] args) throws Exception {
Method main = program.getMethod("main", new Class[]{String[].class});
main.invoke(null, new Object[]{args});
}
protected static String[] programArgs(String[] sourceArgs, int n) {
String[] destArgs = new String[sourceArgs.length - n];
System.arraycopy(sourceArgs, n, destArgs, 0, destArgs.length);
return destArgs;
}
And run it with a command line like this:
java Launcher OtherClassWithMainMethod %CMD_LINE_ARGS%
Calling Runtime.getRuntime().exec() is not only platform specific, it is extremely inefficient. It will result in spawning a brand new shell and an entire jvm which could potentially be very expensive depending on the dependencies of this application (no pun intended).
The best way to execute "external" Java code would be to place it in your CLASSPATH. If you must call an application's main method you can simply import and call the method directly. This could be done like so:
import my.externals.SomeMain
// call as if we are running from console
SomeMain.main(new String[] {"some", "console", "arguments"})
Of course, the best case scenario would be to simply use this as an external library and access the code you need without having to call SomeMain.main(). Adhering to best practices and writing proper encapsulated modular objects allows for much greater portability and ease of use when being used by other applications.
When you leave the JVM and move to system commands, then you have to deal with the platform specific commands yourself. The JVM offers a good way for abstraction, so why move away?
If you want to execute java specific binaries, check out the ant libraries of java. You can execute ant scripts from java which execute platform depending commands.
Java programming from quercus php on GAE:
import com.newatlanta.commons.vfs.provider.gae.GaeVFS;
import org.apache.commons.io.IOUtils;
import java.lang.Long;
import java.lang.Boolean;
GaeVFS::setRootPath(quercus_servlet_request()->getSession(true)->getServletContext()->getRealPath('/'));
define('VFSM', GaeVFS::getManager());
//VFSM->resolveFile('gae://gaevfs')->createFolder();
$file=VFSM->resolveFile('gae://gaevfs/tmp1');
//$file->createFile();
$text='pp';
$method=$file->getClass()->getDeclaredMethod('updateContentSize', array(Long::TYPE, Boolean::TYPE));
$method->setAccessible(true);
$method->invoke($file, strlen($text), true);
$out=$file->getContent()->getOutputStream();
IOUtils::write($text, $out, 'UTF8');
$out->close();
$in=$file->getContent()->getInputStream();
$method=$file->getClass()->getDeclaredMethod('doGetContentSize',array());
$method->setAccessible(true);
$len=$method->invoke($file);
$whole=IOUtils::toString($in, 'UTF8').':'.$len."<br>";
$in->close();
echo $whole;
GaeVFS::clearFilesCache();
GaeVFS::close();