Can picocli subcommands have options with the same name? - picocli

I have a program that executes different types of statistical analysis. I would like to define a subcommand for each type of analysis. The parent command would be the main entry point into the program. I get an error message that says "option should be specified only once" when my subcommands have options with the same name. The problem seems to be how I am calling the subcommands. In the example below, input1 and input2 work correctly. When I try to use both subcommands simultaneously (input3), I get an error message.
The code below demonstrates the problem. If the input contains both subcommands (i.e. input3), I get the error message "option '-id' at index 0 () should be specified only once".
How can I call both subcommands simultaneously as in input3?
import picocli.CommandLine;
import java.util.concurrent.Callable;
#CommandLine.Command(name = "myprogram", subcommands = {TestCase.FrequencyCommand.class, TestCase.HistogramCommand.class})
public class TestCase implements Callable<Void> {
public TestCase(){
}
public Void call() {
System.out.println("Main program called");
return null;
}
public static void main(String[] args){
String[] input1 = {"frequency", "-id", "1001", "-table", "ex1"};
String[] input2 = {"histogram", "-id", "1002", "-table", "ex5" };
String[] input3 = {"frequency", "-id", "1001", "-table", "ex1", "histogram", "-id", "1002", "-table", "ex5" };
CommandLine commandLine = new CommandLine(new TestCase());
System.out.println("==Test1==");
commandLine.execute(input1);
System.out.println();
System.out.println("==Test2==");
commandLine.execute(input2);
System.out.println();
System.out.println("==Test3==");
commandLine.execute(input3);
System.out.println();
}
#CommandLine.Command(name = "frequency", description = "Frequency analysis.")
static class FrequencyCommand implements Callable<Void> {
#CommandLine.Option(names = {"-id"}, arity = "1..*", description = "Unique case identifier")
public String id;
#CommandLine.Option(names = "-table", arity = "1..*", description = "Database table")
public String table;
public FrequencyCommand(){
}
public Void call() {
System.out.println("Frequency");
System.out.println("ID = " + id);
System.out.println("Table = " + table);
return null;
}
}
#CommandLine.Command(name = "histogram", description = "Histogram plot.")
static class HistogramCommand implements Callable<Void> {
#CommandLine.Option(names = {"-id"}, arity = "1..*", description = "Unique case identifier")
public String id;
#CommandLine.Option(names = "-table", arity = "1..*", description = "Database table")
public String table;
public HistogramCommand(){
}
public Void call() {
System.out.println("Histogram");
System.out.println("ID = " + id);
System.out.println("Table = " + table);
return null;
}
}
}
The output I expect to see is:
==Test1==
Frequency
ID = 1001
Table = ex1
==Test2==
Histogram
ID = 1002
Table = ex5
==Test3==
Frequency
ID = 1001
Table = ex1
Histogram
ID = 1002
Table = ex5

The last example invokes two subcommands, frequency and histogram, which are siblings (they have the same parent command).
This is not supported yet as of picocli 4.0.0-alpha-3: currently picocli expects subcommands to be a hierarchy.
However, support for this is on the todo list, see GitHub tickets #454 and #319.
Pull requests are welcome if you want to help speed things up. :-)

Related

PicoCLI : How can I use #ArgGroup for a method?

I want to have mutually exclusive command options for the below snippet :
#Command(description = "test command")
public void test(
#Option(names = { "-a"}, required = true, arity = "0", description = "print A") boolean a,
#Option(names = { "-b"}, required = true, description = "pint B") boolean b)
//
}
If I use #ArgGroup for a class field then It works but I want to achieve the same for methods.
class TestClass{
#ArgGroup(exclusive = true, multiplicity = "1")
private Sample sample = new Sample();
public static class Sample {
#Option(names = { "-a"}, required = true, arity = "0", description = "print A") boolean a ;
#Option(names = { "-b"}, required = true, description = "pint B") boolean b ;
}
}
You should be able to use an #ArgGroup-annotated method, just like an #ArgGroup-annotated field.
For example:
class SomeCommand implements Runnable {
private Sample sample;
#ArgGroup(exclusive = true, multiplicity = "1")
void setGroup(Sample sample) {
System.out.printf("setGroup was called with %s%n", sample);
this.sample = sample;
}
static class Sample {
#Option(names = "-a", required = true, arity = "0", description = "print A") boolean a ;
#Option(names = "-b", required = true, description = "print B") boolean b ;
public String toString() {
return String.format("Sample[a=%s, b=%s]#%x", a, b, hashCode());
}
}
public void run() {
System.out.printf("In run, sample=%s%n", this.sample);
}
public static void main(String... args) {
//System.setProperty("picocli.trace", "DEBUG");
new CommandLine(new SomeCommand()).execute("-a");
}
}
When I run this, I see the following output:
setGroup was called with Sample[a=false, b=false]#7de62196
In run, sample=Sample[a=true, b=false]#7de62196
So, you can use an #ArgGroup-annotated method; it will initially be invoked with a new instance, and this instance will be modified after the setter method was called.
(We can get more insight into what is happening under the hood by enabling picocli tracing.)

picocli example showing the usage of multiple commands

ive got some code that works very well with picocli:
#Command(name = "parse", sortOptions = false, description = "parse input files and write to database")
class CommandLineArgumentParser {
#Option(names = { "-h", "--help" }, usageHelp = true, description = "display this message")
private boolean helpRequested = false;
#Option(names = { "-s", "--startDate"}, description = "First day at which to parse data",
converter = GermanDateConverter.class, paramLabel = "dd.MM.yyyy")
public LocalDate start;
#Option(names = { "-e", "--endDate"}, description = "Last day (inclusive) at which to stop parsing",
converter = GermanDateConverter.class, paramLabel = "dd.MM.yyyy")
public LocalDate end;
private static class GermanDateConverter implements ITypeConverter<LocalDate> {
#Override
public LocalDate convert(String value) throws Exception {
LocalDate result = null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
result = LocalDate.parse(value, formatter);
if (result.getYear() < 1900) {
throw new IllegalArgumentException("year should be after 1900");
}
return result;
}
}
#SpringBootApplication
public class Application implements CommandLineRunner {
public void run(String... args) throws Exception {
CommandLineArgumentParser commandlineparser = new CommandLineArgumentParser();
CommandLine commandLine = new CommandLine(commandlineparser);
try {
commandLine.parseArgs(args);
} catch (MissingParameterException e) {
System.out.println(e);
System.out.println();
CommandLine.usage(CommandLineArgumentParser.class, System.out);
System.exit(1);
} catch (ParameterException e) {
System.out.println(e);
System.out.println();
CommandLine.usage(CommandLineArgumentParser.class, System.out);
System.exit(1);
}
if (commandLine.isUsageHelpRequested()) {
commandLine.usage(System.out);
return;
} else if (commandLine.isVersionHelpRequested()) {
commandLine.printVersionHelp(System.out);
return;
}
if (commandlineparser.start == null) {
log.warn("no start date specified, using: 01.01.2005");
commandlineparser.start = LocalDate.of(2005, 01, 01);
}
if (commandlineparser.end == null) {
LocalDate timePoint = LocalDate.now();
log.warn("no end date specified, using today: " + timePoint.toString());
commandlineparser.end = timePoint;
}
}
but i did not find a simple example that shows multiple commands used, for example this one:
https://github.com/remkop/picocli/blob/master/src/test/java/picocli/Demo.java
does not compile:
int exitCode = new CommandLine(new Demo()).execute(args);
The method execute(CommandLine, List<Object>) in the type CommandLine is not applicable for the arguments (String[])
could somebody please post a example on howto use multiple commands?
I suspect you’re using an older version of the library. The execute(String []) : int method was introduced in picocli 4.0.
Upgrading and using the execute method instead of the parseArgs method will allow you to remove a lot of boilerplate code from the application: handling requests for usage/version help and dealing with invalid input is done automatically with the execute method.
Your commands should implement Runnable or Callable, and this is where the business logic of each command lives.
Modifying your example and giving it a subcommand:
#Command(name = "parse", sortOptions = false,
mixinStandardHelpOptions = true, version = “1.0”,
description = "parse input files and write to database",
subcommands = MySubcommand.class)
class CommandLineArgumentParser implements Callable<Integer> {
#Option(names = { "-s", "--startDate"}, description = "First day at which to parse data",
converter = GermanDateConverter.class, paramLabel = "dd.MM.yyyy")
public LocalDate start;
#Option(names = { "-e", "--endDate"}, description = "Last day (inclusive) at which to stop parsing",
converter = GermanDateConverter.class, paramLabel = "dd.MM.yyyy")
public LocalDate end;
private static class GermanDateConverter implements ITypeConverter<LocalDate> {
#Override
public LocalDate convert(String value) throws Exception {
LocalDate result = null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
result = LocalDate.parse(value, formatter);
if (result.getYear() < 1900) {
throw new IllegalArgumentException("year should be after 1900");
}
return result;
}
}
#Override
public Integer call() {
if (start == null) {
log.warn("no start date specified, using: 01.01.2005");
start = LocalDate.of(2005, 01, 01);
}
if (end == null) {
LocalDate timePoint = LocalDate.now();
log.warn("no end date specified, using today: " + timePoint.toString());
end = timePoint;
}
// more business logic here ...
// add finally return an exit code
int exitCode = ok ? 0 : 1;
return exitCode;
}
}
#Command(name = "foo")
class MySubcommand implements Callable<Integer> {
#Override
public Integer call() {
System.out.println("hi");
return 0;
}
}
#SpringBootApplication
public class Application implements CommandLineRunner {
public void run(String... args) throws Exception {
int exitCode = new CommandLine(
CommandLineArgumentParser.class,
new picocli.spring.PicocliSpringFactory())
.execute(args);
System.exit(exitCode);
}
}
Note that when using Spring in combination with picocli subcommands, you need to call the CommandLine constructor with a picocli.spring.PicocliSpringFactory.
For a more complete Spring example, see the picocli-spring-boot-starter README.

How do I create a dynamic Linq query to fill an ASP.NET databound ListView?

I am having some trouble figuring out the right way to go about creating a dynamic query that I can use values from DropDownList controls to filter and sort/order the results of a database query to fill a ListView. I am able to hard code individual queries, which works ok, except for the fact that it takes an incredible amount of effort, and is not easily changed.
My code is as follows (using all filters):
queryResult = From product In myEntities.InventoryProducts
Where product.VendorID = ddlFilterVendor.SelectedValue And product.ItemType = ddlItemType.SelectedValue And product.LabelSize = ddlLabelSize.SelectedValue And product.PrintLabel = boolPrint And product.Edited = boolEdited
Order By product.ID Ascending
Select product
Return queryResult
Is there a better method to this? I would like to be able to select the value from each DropDownList and generate a custom WHERE clause, as well as an ORDER BY clause.
Any help would be greatly appreciated, thanks.
I can give you a simple example as to how to to proceed with your idea. I am sure if you look through StackOverflow or search via google you will get code that does a better job of dynamic expression building. The same concept can be used for order by.
void Main()
{
var ops = new List<Ops>
{
new Ops
{
OperandType = typeof(string),
OpType=OpType.Equals,
OperandName = "Name",
ValueToCompare = "MM" // in your case this will be the values from the dropdowns
},
new Ops
{
OperandType = typeof(int),
OpType=OpType.Equals,
OperandName = "ID",
ValueToCompare = 1
},
};
var testClasses = new List<TestClass>
{
new TestClass { ID =1, Name = "MM", Date = new DateTime(2014,12,1)},
new TestClass { ID =2, Name = "BB", Date = new DateTime(2014,12,2)}
};
// this will produce prop => ((prop.Name == "MM") And (prop.ID == 1))
var whereDelegate = ExpressionBuilder.BuildExpressions<TestClass>(ops);
foreach(var item in testClasses.Where(whereDelegate))
{
Console.WriteLine("ID " +item.ID);
Console.WriteLine("Name " +item.Name);
Console.WriteLine("Date" + item.Date);
}
}
// Define other methods and classes here
public enum OpType
{
Equals
}
public class Ops
{
public Type OperandType {get; set;}
public OpType OpType {get; set;}
public string OperandName {get;set;}
public object ValueToCompare {get;set;}
}
public class TestClass
{
public int ID {get;set;}
public string Name {get; set;}
public DateTime Date {get;set;}
}
public class ExpressionBuilder
{
public static Func<T,bool> BuildExpressions<T>( List<Ops> opList)
{
Expression currentExpression= null;
var parameterExpression = Expression.Parameter(typeof(T), "prop");
for(int i =0; i< opList.Count; i++)
{
var op = opList[i];
Expression innerExpression = null;
switch(op.OpType)
{
case OpType.Equals :
{
var propertyExpression = Expression.Property(parameterExpression ,
op.OperandName);
var constExpression = Expression.Constant(op.ValueToCompare);
innerExpression = Expression.Equal(propertyExpression,
constExpression);
break;
}
}
if (i >0)
{
currentExpression = Expression.And(currentExpression, innerExpression);
}
else
{
currentExpression = innerExpression;
}
}
var lambdaExpression = Expression.Lambda<Func<T,bool>>(currentExpression,
new []{parameterExpression });
Console.WriteLine(lambdaExpression);
return lambdaExpression.Compile() ;
}
}

ActiveAndroid NPE from execute

I am following https://github.com/pardom/ActiveAndroid/wiki/Querying-the-database to incorporate activeandroid in my application like so:
#Table(name="Contact")
public class Contact extends Model implements Serializable, Comparable {
public Contact() {
super();
}
public Contact(String id, String n, String c, String p, String addr, String phone,
String fb, String twit, String yt) {
super();
candID = id;
name = n;
chamber = c;
party = p;
address = addr;
phoneNo = phone;
facebook = fb;
twitter = twit;
youtube = yt;
}
public static List<Contact> getCachedContactsByState(String stateAbbr) {
/*return new Select().from(Contact.class).where("state = ?",
stateAbbr).execute();*/
Select s = new Select();
From f = s.from(Contact.class);
f = f.where("state = ?", stateAbbr);
List<Contact> cachedContacts = f.execute();
return cachedContacts;
}
According to my debugger, the f.execute throws a null pointer exception, and f is not null.
just making sure, the tutorial didn't mention needing to install sqlite before using activeandroid, and it said the point of activeandroid was to use objects and their functions to do CRUD on sqlite, so I'm assuming I just needed to follow the tutorial to create and query my sqlite db?
Looks like you've forgotten to call ActiveAndroid.initialize() with a valid Context. See the Getting Started section from the documentation you linked to.

How to dynamically use getters/setters in Dart

class User{
String firstName;
String lastName;
String email;
}
I want to be able to get and set one of the fields in user with a dynamically selected symbol or string. For example String value = u[new Symbol("firstName")];
I see that InstanceMirror has a getField method, but it doesn't seem to return the value. All I need is the value.
If you create a symbol with # you need to know the name at compile time.
I got it working this way:
library operator_lib;
import 'dart:mirrors';
void main(List<String> args) {
var x = new X();
var f = new Symbol('firstName');
var r = reflect(x);
print(r.getField(f).reflectee);
r.setField(f, "John");
print(r.getField(f).reflectee);
}
class X {
String firstName = 'Mike';
}

Resources