From e9229f961b3a5799f6798369afe26dec7960249c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 12 Jul 2010 22:42:25 -0700 Subject: Initial commit --- src/main/java/com/beust/jcommander/JCommander.java | 194 +++++++++++++++++++++ src/main/java/com/beust/jcommander/Lists.java | 20 +++ src/main/java/com/beust/jcommander/Maps.java | 11 ++ src/main/java/com/beust/jcommander/Parameter.java | 15 ++ .../com/beust/jcommander/ParameterDescription.java | 69 ++++++++ .../com/beust/jcommander/ParameterException.java | 9 + src/main/java/com/beust/jcommander/Sets.java | 12 ++ 7 files changed, 330 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/JCommander.java create mode 100644 src/main/java/com/beust/jcommander/Lists.java create mode 100644 src/main/java/com/beust/jcommander/Maps.java create mode 100644 src/main/java/com/beust/jcommander/Parameter.java create mode 100644 src/main/java/com/beust/jcommander/ParameterDescription.java create mode 100644 src/main/java/com/beust/jcommander/ParameterException.java create mode 100644 src/main/java/com/beust/jcommander/Sets.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java new file mode 100644 index 0000000..9355749 --- /dev/null +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -0,0 +1,194 @@ +package com.beust.jcommander; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +public class JCommander { + private Map m_descriptions; + private Object m_object; + + /** This field will contain whatever command line parameter is not an option. + * It is expected to be a List. + */ + private Field m_mainParameterField; + + public JCommander(Object object) { + m_object = object; + } + + public JCommander(Object object, String[] args) { + m_object = object; + parse(args); + } + + /** + * Parse the command line parameters. + */ + public void parse(String[] args) { + createDescriptions(); + parseValues(expandArgs(args)); + } + + /** + * Expand the command line parameters to take @ parameters into account. + * When @ is encountered, the content of the file that follows is inserted + * in the command line + * @param originalArgv the original command line parameters + * @return the new and enriched command line parameters + */ + private static String[] expandArgs(String[] originalArgv) { + List vResult = Lists.newArrayList(); + + for (String arg : originalArgv) { + + if (arg.startsWith("@")) { + String fileName = arg.substring(1); + vResult.addAll(readFile(fileName)); + } + else { + vResult.add(arg); + } + } + + return vResult.toArray(new String[vResult.size()]); + } + + /** + * Reads the file specified by filename and returns the file content as a string. + * End of lines are replaced by a space + * + * @param fileName the command line filename + * @return the file content as a string. + */ + public static List readFile(String fileName) { + List result = Lists.newArrayList(); + + try { + BufferedReader bufRead = new BufferedReader(new FileReader(fileName)); + + String line; + + // Read through file one line at time. Print line # and line + while ((line = bufRead.readLine()) != null) { + result.add(line); + } + + bufRead.close(); + } + catch (IOException e) { + throw new ParameterException("Could not read file " + fileName + ": " + e); + } + + return result; + } + + /** + * @param string + * @return + */ + private static String trim(String string) { + String result = string.trim(); + if (result.startsWith("\"")) { + if (result.endsWith("\"")) { + return result.substring(1, result.length() - 1); + } else { + return result.substring(1); + } + } else { + return result; + } + } + + private void createDescriptions() { + m_descriptions = Maps.newHashMap(); + Class cls = m_object.getClass(); + for (Field f : cls.getDeclaredFields()) { + p("Field:" + f.getName()); + f.setAccessible(true); + Annotation annotation = f.getAnnotation(Parameter.class); + if (annotation != null) { + Parameter p = (Parameter) annotation; + if (p.names().length == 0) { + p("Found main parameter:" + f); + m_mainParameterField = f; + } else { + for (String name : p.names()) { + p("Adding description for " + name); + ParameterDescription pd = new ParameterDescription(m_object, p, f); + m_descriptions.put(name, pd); + } + } + } + } + } + + private void p(String string) { + if (false) { + System.out.println("[JCommander] " + string); + } + } + + private void parseValues(String[] args) { + for (int i = 0; i < args.length; i++) { + String a = trim(args[i]); + if (a.startsWith("-")) { + ParameterDescription pd = m_descriptions.get(a); + if (pd != null) { + Class fieldType = pd.getField().getType(); + if (fieldType == boolean.class || fieldType == Boolean.class) { + pd.addValue(Boolean.TRUE); + } else if (i + 1 < args.length) { + pd.addValue(trim(args[i + 1])); + i++; + } else { + throw new ParameterException("Parameter expected after " + args[i]); + } + } else { + throw new ParameterException("Unknown option: " + a); + } + } + else { + if (! isStringEmpty(args[i])) getMainParameter().add(args[i]); + } + } + } + + private static boolean isStringEmpty(String s) { + return s == null || "".equals(s); + } + + private List getMainParameter() { + if (m_mainParameterField == null) { + throw new ParameterException( + "Non option parameters were found but no main parameter was defined"); + } + + try { + List result = (List) m_mainParameterField.get(m_object); + if (result == null) { + result = Lists.newArrayList(); + m_mainParameterField.set(m_object, result); + } + return result; + } + catch(IllegalAccessException ex) { + throw new ParameterException("Couldn't access main parameter: " + ex.getMessage()); + } + } + + public void usage() { + System.out.println("Usage:"); + for (ParameterDescription pd : m_descriptions.values()) { + StringBuilder sb = new StringBuilder(); + for (String n : pd.getNames()) { + sb.append(n).append(" "); + } + System.out.println("\t" + sb.toString() + "\t" + pd.getDescription()); + } + } +} diff --git a/src/main/java/com/beust/jcommander/Lists.java b/src/main/java/com/beust/jcommander/Lists.java new file mode 100644 index 0000000..5794beb --- /dev/null +++ b/src/main/java/com/beust/jcommander/Lists.java @@ -0,0 +1,20 @@ +package com.beust.jcommander; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class Lists { + + public static List newArrayList() { + return new ArrayList(); + } + + public static List newArrayList(Collection c) { + return new ArrayList(c); + } + + public static List newArrayList(int size) { + return new ArrayList(size); + } +} diff --git a/src/main/java/com/beust/jcommander/Maps.java b/src/main/java/com/beust/jcommander/Maps.java new file mode 100644 index 0000000..1442e85 --- /dev/null +++ b/src/main/java/com/beust/jcommander/Maps.java @@ -0,0 +1,11 @@ +package com.beust.jcommander; + +import java.util.HashMap; +import java.util.Map; + +public class Maps { + + public static Map newHashMap() { + return new HashMap(); + } +} diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java new file mode 100644 index 0000000..9e6bc6a --- /dev/null +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -0,0 +1,15 @@ +package com.beust.jcommander; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ FIELD }) +public @interface Parameter { + + String[] names() default {}; + + String description() default ""; +} diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java new file mode 100644 index 0000000..e44c0cb --- /dev/null +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -0,0 +1,69 @@ +package com.beust.jcommander; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Set; + +public class ParameterDescription { + private Object m_object; + private Parameter m_parameterAnnotation; + private Field m_field; + /** Keep track of whether a value was added to flag an error */ + private boolean m_added = false; + + public ParameterDescription(Object object, Parameter annotation, Field field) { + m_object = object; + m_parameterAnnotation = annotation; + m_field = field; + } + + public String[] getNames() { + return m_parameterAnnotation.names(); + } + + public String getDescription() { + return m_parameterAnnotation.description(); + } + + public Field getField() { + return m_field; + } + + private boolean isMultiOption() { + Class fieldType = m_field.getType(); + return fieldType.equals(List.class) || fieldType.equals(Set.class); + } + + public void addValue(Object value) { + if (m_added && ! isMultiOption()) { + throw new ParameterException("Can only specify option " + getNames()[0] + " once."); + } + + m_added = true; + try { + Class fieldType = m_field.getType(); + if (fieldType.equals(String.class)) { + m_field.set(m_object, value); + } else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) { + m_field.set(m_object, Integer.parseInt(value.toString())); + } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) { + m_field.set(m_object, Long.parseLong(value.toString())); + } else if (fieldType.equals(float.class) || fieldType.equals(Float.class)) { + m_field.set(m_object, Float.parseFloat(value.toString())); + } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) { + m_field.set(m_object, value); + } else if (isMultiOption()) { + List l = (List) m_field.get(m_object); + if (l == null) { + l = Lists.newArrayList(); + m_field.set(m_object, l); + } + l.add(value); + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java new file mode 100644 index 0000000..5004cd0 --- /dev/null +++ b/src/main/java/com/beust/jcommander/ParameterException.java @@ -0,0 +1,9 @@ +package com.beust.jcommander; + +public class ParameterException extends RuntimeException { + + public ParameterException(String string) { + super(string); + } + +} diff --git a/src/main/java/com/beust/jcommander/Sets.java b/src/main/java/com/beust/jcommander/Sets.java new file mode 100644 index 0000000..5e7c3ef --- /dev/null +++ b/src/main/java/com/beust/jcommander/Sets.java @@ -0,0 +1,12 @@ +package com.beust.jcommander; + +import java.util.HashSet; +import java.util.Set; + +public class Sets { + + public static Set newHashSet() { + return new HashSet(); + } + +} -- cgit v1.2.3 From 5a3441b747c98f5b32e58b5a64fcb02fed5836fe Mon Sep 17 00:00:00 2001 From: David Gageot Date: Tue, 13 Jul 2010 17:03:10 +0200 Subject: Accept arguments as varargs --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9355749..88e5225 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -21,7 +21,7 @@ public class JCommander { m_object = object; } - public JCommander(Object object, String[] args) { + public JCommander(Object object, String... args) { m_object = object; parse(args); } @@ -29,7 +29,7 @@ public class JCommander { /** * Parse the command line parameters. */ - public void parse(String[] args) { + public void parse(String... args) { createDescriptions(); parseValues(expandArgs(args)); } -- cgit v1.2.3 From 696418a94157048544c44f405d757ede86eec926 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 13 Jul 2010 20:28:54 -0700 Subject: Fixed a bug that showed duplicate lines in usage() --- src/main/java/com/beust/jcommander/JCommander.java | 46 ++++++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 88e5225..f048906 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -5,18 +5,40 @@ import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.util.Collection; import java.util.List; import java.util.Map; +/** + * The main class for JCommander. It's responsible for parsing the object that contains + * all the annotated fields, parse the command line and assign the fields with the correct + * values and a few other helper methods, such as usage(). + * + * @author cbeust + * + */ public class JCommander { + /** + * A map to look up parameter description per option name. + */ private Map m_descriptions; + + /** + * The object that contains the fields annotated with @Parameter. + */ private Object m_object; - /** This field will contain whatever command line parameter is not an option. + /** + * This field will contain whatever command line parameter is not an option. * It is expected to be a List. */ private Field m_mainParameterField; + /** + * A map of all the fields that describe an option. + */ + private Map m_fields = Maps.newHashMap(); + public JCommander(Object object) { m_object = object; } @@ -113,6 +135,9 @@ public class JCommander { Annotation annotation = f.getAnnotation(Parameter.class); if (annotation != null) { Parameter p = (Parameter) annotation; + if (p.names().length > 0) { + m_fields.put(f, p); + } if (p.names().length == 0) { p("Found main parameter:" + f); m_mainParameterField = f; @@ -181,14 +206,27 @@ public class JCommander { } } + /** + * Display a the help on System.out. + */ public void usage() { System.out.println("Usage:"); - for (ParameterDescription pd : m_descriptions.values()) { + for (Parameter p : m_fields.values()) { StringBuilder sb = new StringBuilder(); - for (String n : pd.getNames()) { + for (String n : p.names()) { sb.append(n).append(" "); } - System.out.println("\t" + sb.toString() + "\t" + pd.getDescription()); + System.out.println("\t" + sb.toString() + "\t" + p.description()); } } + + /** + * @return a Collection of all the @Parameter annotations found on the + * target class. This can be used to display the usage() in a different + * format (e.g. HTML). + */ + public Collection getParameters() { + return m_fields.values(); + } } + -- cgit v1.2.3 From dc76d5707bd6f5b761772203e9d7c285846e8362 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 13 Jul 2010 21:11:57 -0700 Subject: Added required and tests --- src/main/java/com/beust/jcommander/JCommander.java | 39 ++++++++++++++++++---- src/main/java/com/beust/jcommander/Parameter.java | 13 ++++++++ .../com/beust/jcommander/ParameterDescription.java | 4 +++ 3 files changed, 50 insertions(+), 6 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f048906..7fc3a5f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -8,6 +8,7 @@ import java.lang.reflect.Field; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; /** * The main class for JCommander. It's responsible for parsing the object that contains @@ -15,7 +16,6 @@ import java.util.Map; * values and a few other helper methods, such as usage(). * * @author cbeust - * */ public class JCommander { /** @@ -35,7 +35,17 @@ public class JCommander { private Field m_mainParameterField; /** - * A map of all the fields that describe an option. + * A set of all the fields that are required. During the reflection phase, + * this field receives all the fields that are annotated with required=true + * and during the parsing phase, all the fields that are assigned a value + * are removed from it. At the end of the parsing phase, if it's not empty, + * then some required fields did not receive a value and an exception is + * thrown. + */ + private Map m_requiredFields = Maps.newHashMap(); + + /** + * A map of all the annotated fields. */ private Map m_fields = Maps.newHashMap(); @@ -54,12 +64,28 @@ public class JCommander { public void parse(String... args) { createDescriptions(); parseValues(expandArgs(args)); + validateOptions(); } + /** + * Make sure that all the required parameters have received a value. + */ + private void validateOptions() { + if (! m_requiredFields.isEmpty()) { + StringBuilder missingFields = new StringBuilder(); + for (ParameterDescription pd : m_requiredFields.values()) { + missingFields.append(pd.getNames()[0]).append(" "); + } + throw new ParameterException("The following options are required: " + missingFields); + } + + } + /** * Expand the command line parameters to take @ parameters into account. * When @ is encountered, the content of the file that follows is inserted - * in the command line + * in the command line. + * * @param originalArgv the original command line parameters * @return the new and enriched command line parameters */ @@ -135,9 +161,6 @@ public class JCommander { Annotation annotation = f.getAnnotation(Parameter.class); if (annotation != null) { Parameter p = (Parameter) annotation; - if (p.names().length > 0) { - m_fields.put(f, p); - } if (p.names().length == 0) { p("Found main parameter:" + f); m_mainParameterField = f; @@ -145,7 +168,9 @@ public class JCommander { for (String name : p.names()) { p("Adding description for " + name); ParameterDescription pd = new ParameterDescription(m_object, p, f); + m_fields.put(f, p); m_descriptions.put(name, pd); + if (p.required()) m_requiredFields.put(f, pd); } } } @@ -167,8 +192,10 @@ public class JCommander { Class fieldType = pd.getField().getType(); if (fieldType == boolean.class || fieldType == Boolean.class) { pd.addValue(Boolean.TRUE); + m_requiredFields.remove(pd.getField()); } else if (i + 1 < args.length) { pd.addValue(trim(args[i + 1])); + m_requiredFields.remove(pd.getField()); i++; } else { throw new ParameterException("Parameter expected after " + args[i]); diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 9e6bc6a..bd1ea88 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -9,7 +9,20 @@ import java.lang.annotation.Target; @Target({ FIELD }) public @interface Parameter { + /** + * An array of allowed command line parameters (e.g. "-d", "--outputdir", etc...). + * If this attribute is omitted, the field it's annotating will receive all the + * unparsed options. There can only be at most one such annotation. + */ String[] names() default {}; + /** + * A description of this option. + */ String description() default ""; + + /** + * Whether this option is required. + */ + boolean required() default false; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index e44c0cb..5308591 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -25,6 +25,10 @@ public class ParameterDescription { return m_parameterAnnotation.description(); } + public Parameter getParameter() { + return m_parameterAnnotation; + } + public Field getField() { return m_field; } -- cgit v1.2.3 From 9b9a740c04d97ccbb5c643e55775cf9e9e6fc2d7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 13 Jul 2010 23:13:03 -0700 Subject: Added support for i18n --- src/main/java/com/beust/jcommander/JCommander.java | 28 ++++++++++++++-------- src/main/java/com/beust/jcommander/Parameter.java | 5 ++++ .../com/beust/jcommander/ParameterDescription.java | 20 ++++++++++++++-- 3 files changed, 41 insertions(+), 12 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7fc3a5f..24a801f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -5,10 +5,10 @@ import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; -import java.util.Collection; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.ResourceBundle; /** * The main class for JCommander. It's responsible for parsing the object that contains @@ -47,12 +47,20 @@ public class JCommander { /** * A map of all the annotated fields. */ - private Map m_fields = Maps.newHashMap(); + private Map m_fields = Maps.newHashMap(); + + private ResourceBundle m_bundle; public JCommander(Object object) { m_object = object; } + public JCommander(Object object, ResourceBundle bundle, String... args) { + m_object = object; + m_bundle = bundle; + parse(args); + } + public JCommander(Object object, String... args) { m_object = object; parse(args); @@ -167,8 +175,8 @@ public class JCommander { } else { for (String name : p.names()) { p("Adding description for " + name); - ParameterDescription pd = new ParameterDescription(m_object, p, f); - m_fields.put(f, p); + ParameterDescription pd = new ParameterDescription(m_object, p, f, m_bundle); + m_fields.put(f, pd); m_descriptions.put(name, pd); if (p.required()) m_requiredFields.put(f, pd); } @@ -238,12 +246,12 @@ public class JCommander { */ public void usage() { System.out.println("Usage:"); - for (Parameter p : m_fields.values()) { + for (ParameterDescription pd : m_fields.values()) { StringBuilder sb = new StringBuilder(); - for (String n : p.names()) { + for (String n : pd.getParameter().names()) { sb.append(n).append(" "); } - System.out.println("\t" + sb.toString() + "\t" + p.description()); + System.out.println("\t" + sb.toString() + "\t" + pd.getDescription()); } } @@ -252,8 +260,8 @@ public class JCommander { * target class. This can be used to display the usage() in a different * format (e.g. HTML). */ - public Collection getParameters() { - return m_fields.values(); + public List getParameters() { + return new ArrayList(m_fields.values()); } } diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index bd1ea88..6536a9f 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -25,4 +25,9 @@ public @interface Parameter { * Whether this option is required. */ boolean required() default false; + + /** + * The key used to find the string in the message bundle. + */ + String descriptionKey() default ""; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 5308591..8088272 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,7 +1,9 @@ package com.beust.jcommander; + import java.lang.reflect.Field; import java.util.List; +import java.util.ResourceBundle; import java.util.Set; public class ParameterDescription { @@ -10,11 +12,25 @@ public class ParameterDescription { private Field m_field; /** Keep track of whether a value was added to flag an error */ private boolean m_added = false; + private ResourceBundle m_bundle; + private String m_description; + + public ParameterDescription(Object object, Parameter annotation, Field field, + ResourceBundle bundle) { + init(object, annotation, field, bundle); + } - public ParameterDescription(Object object, Parameter annotation, Field field) { + private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle) { m_object = object; m_parameterAnnotation = annotation; m_field = field; + m_bundle = bundle; + + if (m_bundle != null) { + m_description = m_bundle.getString(annotation.descriptionKey()); + } else { + m_description = annotation.description(); + } } public String[] getNames() { @@ -22,7 +38,7 @@ public class ParameterDescription { } public String getDescription() { - return m_parameterAnnotation.description(); + return m_description; } public Parameter getParameter() { -- cgit v1.2.3 From d4e3897873895131ae5ebef4e9552b15a9e804dd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 14 Jul 2010 09:19:53 -0700 Subject: Added multi object support and tests --- src/main/java/com/beust/jcommander/JCommander.java | 81 +++++++++++++++------- 1 file changed, 56 insertions(+), 25 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 24a801f..c5a25f4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -24,9 +25,9 @@ public class JCommander { private Map m_descriptions; /** - * The object that contains the fields annotated with @Parameter. + * The objects that contain fields annotated with @Parameter. */ - private Object m_object; + private List m_objects; /** * This field will contain whatever command line parameter is not an option. @@ -34,6 +35,11 @@ public class JCommander { */ private Field m_mainParameterField; + /** + * The object on which we found the main parameter field. + */ + private Object m_mainParameterObject; + /** * A set of all the fields that are required. During the reflection phase, * this field receives all the fields that are annotated with required=true @@ -52,20 +58,38 @@ public class JCommander { private ResourceBundle m_bundle; public JCommander(Object object) { - m_object = object; + init(object, null); } public JCommander(Object object, ResourceBundle bundle, String... args) { - m_object = object; - m_bundle = bundle; + init(object, bundle); parse(args); } public JCommander(Object object, String... args) { - m_object = object; + init(object, null); parse(args); } + private void init(Object object, ResourceBundle bundle) { + m_bundle = bundle; + m_objects = Lists.newArrayList(); + if (object instanceof Iterable) { + // Iterable + for (Object o : (Iterable) object) { + m_objects.add(o); + } + } else if (object.getClass().isArray()) { + // Array + for (Object o : (Object[]) object) { + m_objects.add(o); + } + } else { + // Single object + m_objects.add(object); + } + } + /** * Parse the command line parameters. */ @@ -162,23 +186,27 @@ public class JCommander { private void createDescriptions() { m_descriptions = Maps.newHashMap(); - Class cls = m_object.getClass(); - for (Field f : cls.getDeclaredFields()) { - p("Field:" + f.getName()); - f.setAccessible(true); - Annotation annotation = f.getAnnotation(Parameter.class); - if (annotation != null) { - Parameter p = (Parameter) annotation; - if (p.names().length == 0) { - p("Found main parameter:" + f); - m_mainParameterField = f; - } else { - for (String name : p.names()) { - p("Adding description for " + name); - ParameterDescription pd = new ParameterDescription(m_object, p, f, m_bundle); - m_fields.put(f, pd); - m_descriptions.put(name, pd); - if (p.required()) m_requiredFields.put(f, pd); + + for (Object object : m_objects) { + Class cls = object.getClass(); + for (Field f : cls.getDeclaredFields()) { + p("Field:" + f.getName()); + f.setAccessible(true); + Annotation annotation = f.getAnnotation(Parameter.class); + if (annotation != null) { + Parameter p = (Parameter) annotation; + if (p.names().length == 0) { + p("Found main parameter:" + f); + m_mainParameterField = f; + m_mainParameterObject = object; + } else { + for (String name : p.names()) { + p("Adding description for " + name); + ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle); + m_fields.put(f, pd); + m_descriptions.put(name, pd); + if (p.required()) m_requiredFields.put(f, pd); + } } } } @@ -222,6 +250,9 @@ public class JCommander { return s == null || "".equals(s); } + /** + * @return the field that's meant to receive all the parameters that are not options. + */ private List getMainParameter() { if (m_mainParameterField == null) { throw new ParameterException( @@ -229,10 +260,10 @@ public class JCommander { } try { - List result = (List) m_mainParameterField.get(m_object); + List result = (List) m_mainParameterField.get(m_mainParameterObject); if (result == null) { result = Lists.newArrayList(); - m_mainParameterField.set(m_object, result); + m_mainParameterField.set(m_mainParameterObject, result); } return result; } -- cgit v1.2.3 From a21262377768de124914e354e428ed6860828949 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 14 Jul 2010 09:40:39 -0700 Subject: Implemented arity and tests --- src/main/java/com/beust/jcommander/JCommander.java | 16 +++++++++++----- src/main/java/com/beust/jcommander/Parameter.java | 6 ++++++ 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c5a25f4..9b71dfe 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -229,12 +229,18 @@ public class JCommander { if (fieldType == boolean.class || fieldType == Boolean.class) { pd.addValue(Boolean.TRUE); m_requiredFields.remove(pd.getField()); - } else if (i + 1 < args.length) { - pd.addValue(trim(args[i + 1])); - m_requiredFields.remove(pd.getField()); - i++; } else { - throw new ParameterException("Parameter expected after " + args[i]); + int arity = pd.getParameter().arity(); + int n = (arity != -1 ? arity : 1); + if (i + n < args.length) { + for (int j = 1; j <= n; j++) { + pd.addValue(trim(args[i + j])); + m_requiredFields.remove(pd.getField()); + } + i += n; + } else { + throw new ParameterException("Parameter expected after " + args[i]); + } } } else { throw new ParameterException("Unknown option: " + a); diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 6536a9f..721413b 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -30,4 +30,10 @@ public @interface Parameter { * The key used to find the string in the message bundle. */ String descriptionKey() default ""; + + /** + * How many parameter values this parameter will consume. For example, + * an arity of 2 will allow "-pair value1 value2". + */ + int arity() default -1; } -- cgit v1.2.3 From 0c0b2226295308797b486e7dcc81d10497ad4886 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 14 Jul 2010 09:45:49 -0700 Subject: Now failing if the same option is found more than once --- src/main/java/com/beust/jcommander/JCommander.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9b71dfe..7d4db50 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -201,6 +201,9 @@ public class JCommander { m_mainParameterObject = object; } else { for (String name : p.names()) { + if (m_descriptions.containsKey(name)) { + throw new ParameterException("Found the option " + name + " multiple times"); + } p("Adding description for " + name); ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle); m_fields.put(f, pd); -- cgit v1.2.3 From f3b82e196a622a959374d7588688e74fe852a512 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 14 Jul 2010 10:03:30 -0700 Subject: Documented arities and more tests --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7d4db50..7874ce4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -242,7 +242,7 @@ public class JCommander { } i += n; } else { - throw new ParameterException("Parameter expected after " + args[i]); + throw new ParameterException(arity + " parameters expected after " + args[i]); } } } else { -- cgit v1.2.3 From cb91ef843854605fcde3b84ce91ec4d46205a47a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 14 Jul 2010 10:08:56 -0700 Subject: More tests --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7874ce4..5dcb3d6 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -33,7 +33,7 @@ public class JCommander { * This field will contain whatever command line parameter is not an option. * It is expected to be a List. */ - private Field m_mainParameterField; + private Field m_mainParameterField = null; /** * The object on which we found the main parameter field. @@ -197,6 +197,10 @@ public class JCommander { Parameter p = (Parameter) annotation; if (p.names().length == 0) { p("Found main parameter:" + f); + if (m_mainParameterField != null) { + throw new ParameterException("Only one @Parameter with no names attribute is" + + " allowed, found:" + m_mainParameterField + " and " + f); + } m_mainParameterField = f; m_mainParameterObject = object; } else { -- cgit v1.2.3 From 5f00acc5afee348e6f3b3741d5e53ca01e508b3e Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 07:02:51 -0700 Subject: Documented and tested private parameters --- src/main/java/com/beust/jcommander/JCommander.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5dcb3d6..e0588d1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -16,6 +16,11 @@ import java.util.ResourceBundle; * all the annotated fields, parse the command line and assign the fields with the correct * values and a few other helper methods, such as usage(). * + * The object(s) you pass in the constructor are expected to have one or more + * @Parameter annotations on them. You can pass either a single object, an array of objects + * or an instance of Iterable. In the case of an array or Iterable, JCommander will collect + * the @Parameter annotations from all the objects passed in parameter. + * * @author cbeust */ public class JCommander { -- cgit v1.2.3 From d095e39e4a4ba659ec031bd7a4695d48502ba5eb Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 09:29:43 -0700 Subject: Added password and test for private fields --- src/main/java/com/beust/jcommander/JCommander.java | 39 ++++++++++++++-------- src/main/java/com/beust/jcommander/Parameter.java | 6 ++++ 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e0588d1..555e360 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,12 +1,12 @@ package com.beust.jcommander; import java.io.BufferedReader; +import java.io.Console; import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -237,21 +237,32 @@ public class JCommander { if (a.startsWith("-")) { ParameterDescription pd = m_descriptions.get(a); if (pd != null) { - Class fieldType = pd.getField().getType(); - if (fieldType == boolean.class || fieldType == Boolean.class) { - pd.addValue(Boolean.TRUE); - m_requiredFields.remove(pd.getField()); + if (pd.getParameter().password()) { + Console console = System.console(); + if (console == null) { + throw new ParameterException("No console is available to get parameter " + + pd.getNames()[0]); + } + System.out.print("Value for " + pd.getNames()[0] + " (" + pd.getDescription() + "):"); + char[] password = console.readPassword(); + pd.addValue(new String(password)); } else { - int arity = pd.getParameter().arity(); - int n = (arity != -1 ? arity : 1); - if (i + n < args.length) { - for (int j = 1; j <= n; j++) { - pd.addValue(trim(args[i + j])); - m_requiredFields.remove(pd.getField()); - } - i += n; + Class fieldType = pd.getField().getType(); + if (fieldType == boolean.class || fieldType == Boolean.class) { + pd.addValue(Boolean.TRUE); + m_requiredFields.remove(pd.getField()); } else { - throw new ParameterException(arity + " parameters expected after " + args[i]); + int arity = pd.getParameter().arity(); + int n = (arity != -1 ? arity : 1); + if (i + n < args.length) { + for (int j = 1; j <= n; j++) { + pd.addValue(trim(args[i + j])); + m_requiredFields.remove(pd.getField()); + } + i += n; + } else { + throw new ParameterException(arity + " parameters expected after " + args[i]); + } } } } else { diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 721413b..ecefd2a 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -36,4 +36,10 @@ public @interface Parameter { * an arity of 2 will allow "-pair value1 value2". */ int arity() default -1; + + /** + * If true, this parameter is a password and it will be prompted on the console + * (if available). + */ + boolean password() default false; } -- cgit v1.2.3 From b65aee8e0ed696b8c4c71793a57c75b4543ca9c1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 09:43:22 -0700 Subject: Moved classes into internal --- src/main/java/com/beust/jcommander/JCommander.java | 3 +++ src/main/java/com/beust/jcommander/Lists.java | 20 -------------------- src/main/java/com/beust/jcommander/Maps.java | 11 ----------- .../com/beust/jcommander/ParameterDescription.java | 2 ++ src/main/java/com/beust/jcommander/Sets.java | 12 ------------ .../java/com/beust/jcommander/internal/Lists.java | 20 ++++++++++++++++++++ .../java/com/beust/jcommander/internal/Maps.java | 11 +++++++++++ .../java/com/beust/jcommander/internal/Sets.java | 12 ++++++++++++ 8 files changed, 48 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/com/beust/jcommander/Lists.java delete mode 100644 src/main/java/com/beust/jcommander/Maps.java delete mode 100644 src/main/java/com/beust/jcommander/Sets.java create mode 100644 src/main/java/com/beust/jcommander/internal/Lists.java create mode 100644 src/main/java/com/beust/jcommander/internal/Maps.java create mode 100644 src/main/java/com/beust/jcommander/internal/Sets.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 555e360..10f7c22 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,5 +1,8 @@ package com.beust.jcommander; +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; + import java.io.BufferedReader; import java.io.Console; import java.io.FileReader; diff --git a/src/main/java/com/beust/jcommander/Lists.java b/src/main/java/com/beust/jcommander/Lists.java deleted file mode 100644 index 5794beb..0000000 --- a/src/main/java/com/beust/jcommander/Lists.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.beust.jcommander; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class Lists { - - public static List newArrayList() { - return new ArrayList(); - } - - public static List newArrayList(Collection c) { - return new ArrayList(c); - } - - public static List newArrayList(int size) { - return new ArrayList(size); - } -} diff --git a/src/main/java/com/beust/jcommander/Maps.java b/src/main/java/com/beust/jcommander/Maps.java deleted file mode 100644 index 1442e85..0000000 --- a/src/main/java/com/beust/jcommander/Maps.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.beust.jcommander; - -import java.util.HashMap; -import java.util.Map; - -public class Maps { - - public static Map newHashMap() { - return new HashMap(); - } -} diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 8088272..8af24b3 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,6 +1,8 @@ package com.beust.jcommander; +import com.beust.jcommander.internal.Lists; + import java.lang.reflect.Field; import java.util.List; import java.util.ResourceBundle; diff --git a/src/main/java/com/beust/jcommander/Sets.java b/src/main/java/com/beust/jcommander/Sets.java deleted file mode 100644 index 5e7c3ef..0000000 --- a/src/main/java/com/beust/jcommander/Sets.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.beust.jcommander; - -import java.util.HashSet; -import java.util.Set; - -public class Sets { - - public static Set newHashSet() { - return new HashSet(); - } - -} diff --git a/src/main/java/com/beust/jcommander/internal/Lists.java b/src/main/java/com/beust/jcommander/internal/Lists.java new file mode 100644 index 0000000..8cacc33 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/Lists.java @@ -0,0 +1,20 @@ +package com.beust.jcommander.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class Lists { + + public static List newArrayList() { + return new ArrayList(); + } + + public static List newArrayList(Collection c) { + return new ArrayList(c); + } + + public static List newArrayList(int size) { + return new ArrayList(size); + } +} diff --git a/src/main/java/com/beust/jcommander/internal/Maps.java b/src/main/java/com/beust/jcommander/internal/Maps.java new file mode 100644 index 0000000..6a0dba6 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/Maps.java @@ -0,0 +1,11 @@ +package com.beust.jcommander.internal; + +import java.util.HashMap; +import java.util.Map; + +public class Maps { + + public static Map newHashMap() { + return new HashMap(); + } +} diff --git a/src/main/java/com/beust/jcommander/internal/Sets.java b/src/main/java/com/beust/jcommander/internal/Sets.java new file mode 100644 index 0000000..ced1045 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/Sets.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.internal; + +import java.util.HashSet; +import java.util.Set; + +public class Sets { + + public static Set newHashSet() { + return new HashSet(); + } + +} -- cgit v1.2.3 From 5a8d2cda56e06eccac04f985cfb6df4886cb270e Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 10:47:14 -0700 Subject: Implemented type converters --- .../com/beust/jcommander/IStringConverter.java | 10 ++++ src/main/java/com/beust/jcommander/JCommander.java | 6 +- src/main/java/com/beust/jcommander/Parameter.java | 4 ++ .../com/beust/jcommander/ParameterDescription.java | 70 +++++++++++++++++----- .../jcommander/converters/BooleanConverter.java | 12 ++++ .../converters/CommaSeparatedConverter.java | 15 +++++ .../beust/jcommander/converters/FileConverter.java | 14 +++++ .../jcommander/converters/IntegerConverter.java | 12 ++++ .../beust/jcommander/converters/LongConverter.java | 12 ++++ .../beust/jcommander/converters/NoConverter.java | 12 ++++ .../jcommander/converters/StringConverter.java | 12 ++++ 11 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IStringConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/BooleanConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/FileConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/IntegerConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/LongConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/NoConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/StringConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IStringConverter.java b/src/main/java/com/beust/jcommander/IStringConverter.java new file mode 100644 index 0000000..9abd96c --- /dev/null +++ b/src/main/java/com/beust/jcommander/IStringConverter.java @@ -0,0 +1,10 @@ +package com.beust.jcommander; + +/** + * An interface that converts strings to any arbitrary type. + * + * @author cbeust + */ +public interface IStringConverter { + T convert(String value); +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 10f7c22..a14a3e5 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,5 +1,8 @@ package com.beust.jcommander; +import com.beust.jcommander.converters.IntegerConverter; +import com.beust.jcommander.converters.LongConverter; +import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; @@ -10,6 +13,7 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -252,7 +256,7 @@ public class JCommander { } else { Class fieldType = pd.getField().getType(); if (fieldType == boolean.class || fieldType == Boolean.class) { - pd.addValue(Boolean.TRUE); + pd.addValue("true"); m_requiredFields.remove(pd.getField()); } else { int arity = pd.getParameter().arity(); diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index ecefd2a..9d4ef62 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -2,6 +2,8 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; +import com.beust.jcommander.converters.NoConverter; + import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -42,4 +44,6 @@ public @interface Parameter { * (if available). */ boolean password() default false; + + Class converter() default NoConverter.class; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 8af24b3..c314fba 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,14 +1,41 @@ package com.beust.jcommander; +import com.beust.jcommander.converters.BooleanConverter; +import com.beust.jcommander.converters.IntegerConverter; +import com.beust.jcommander.converters.LongConverter; +import com.beust.jcommander.converters.NoConverter; +import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; import java.lang.reflect.Field; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.ResourceBundle; import java.util.Set; public class ParameterDescription { + /** + * A map of converters per class. + */ + private static Map, Class> m_classConverters + = new HashMap() {{ + put(String.class, StringConverter.class); + put(Integer.class, IntegerConverter.class); + put(int.class, IntegerConverter.class); + put(Long.class, LongConverter.class); + put(long.class, LongConverter.class); + put(Boolean.class, BooleanConverter.class); + put(boolean.class, BooleanConverter.class); + }}; + + /** + * A map of converters per field. Will take precedence over the class converter map. + */ + private Map m_fieldConverters = Maps.newHashMap(); + private Object m_object; private Parameter m_parameterAnnotation; private Field m_field; @@ -56,36 +83,49 @@ public class ParameterDescription { return fieldType.equals(List.class) || fieldType.equals(Set.class); } - public void addValue(Object value) { + /** + * Add the specified value to the field. First look up any field converter, then + * any type converter, and if we can't find any, throw an exception. + */ + public void addValue(String value) { + boolean arity = false; if (m_added && ! isMultiOption()) { throw new ParameterException("Can only specify option " + getNames()[0] + " once."); } + Class converterClass = m_parameterAnnotation.converter(); + if (converterClass == NoConverter.class) { + converterClass = m_classConverters.get(m_field.getType()); + } + if (converterClass == null && m_parameterAnnotation.arity() >= 2) { + converterClass = StringConverter.class; + arity = true; + } + if (converterClass == null) { + throw new ParameterException("Don't know how to convert " + value + + " to type " + m_field.getType() + " (field: " + m_field.getName() + ")"); + } m_added = true; + IStringConverter converter; try { - Class fieldType = m_field.getType(); - if (fieldType.equals(String.class)) { - m_field.set(m_object, value); - } else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) { - m_field.set(m_object, Integer.parseInt(value.toString())); - } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) { - m_field.set(m_object, Long.parseLong(value.toString())); - } else if (fieldType.equals(float.class) || fieldType.equals(Float.class)) { - m_field.set(m_object, Float.parseFloat(value.toString())); - } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) { - m_field.set(m_object, value); - } else if (isMultiOption()) { + converter = converterClass.newInstance(); + Object convertedValue = converter.convert(value); + if (arity) { List l = (List) m_field.get(m_object); if (l == null) { l = Lists.newArrayList(); m_field.set(m_object, l); } - l.add(value); + l.add(convertedValue); + } else { + m_field.set(m_object, convertedValue); } - } catch (IllegalArgumentException e) { + } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); } } } diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java new file mode 100644 index 0000000..52cd74c --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +public class BooleanConverter implements IStringConverter { + + @Override + public Boolean convert(String value) { + return Boolean.parseBoolean(value); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java new file mode 100644 index 0000000..44c3455 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java @@ -0,0 +1,15 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +import java.util.Arrays; +import java.util.List; + +public class CommaSeparatedConverter implements IStringConverter> { + + @Override + public List convert(String value) { + return Arrays.asList(value.split(",")); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/FileConverter.java b/src/main/java/com/beust/jcommander/converters/FileConverter.java new file mode 100644 index 0000000..36364fc --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/FileConverter.java @@ -0,0 +1,14 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +import java.io.File; + +public class FileConverter implements IStringConverter { + + @Override + public File convert(String value) { + return new File(value); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java new file mode 100644 index 0000000..2efe058 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +public class IntegerConverter implements IStringConverter { + + @Override + public Integer convert(String value) { + return Integer.parseInt(value); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java new file mode 100644 index 0000000..d14fd23 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +public class LongConverter implements IStringConverter { + + @Override + public Long convert(String value) { + return Long.parseLong(value); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/NoConverter.java b/src/main/java/com/beust/jcommander/converters/NoConverter.java new file mode 100644 index 0000000..bae1898 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/NoConverter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +public class NoConverter implements IStringConverter { + + @Override + public String convert(String value) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/StringConverter.java b/src/main/java/com/beust/jcommander/converters/StringConverter.java new file mode 100644 index 0000000..05fec0e --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/StringConverter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +public class StringConverter implements IStringConverter { + + @Override + public String convert(String value) { + return value; + } + +} -- cgit v1.2.3 From 6734de3a3b73ec9fe6bbfe4f8ba1da9f57264587 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 11:36:41 -0700 Subject: Added @ResourceBundle annotation --- .../com/beust/jcommander/ParameterDescription.java | 21 +++++++++++++++++---- .../java/com/beust/jcommander/ResourceBundle.java | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/ResourceBundle.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index c314fba..64bef39 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -12,6 +12,7 @@ import com.beust.jcommander.internal.Maps; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; @@ -54,11 +55,23 @@ public class ParameterDescription { m_parameterAnnotation = annotation; m_field = field; m_bundle = bundle; + if (m_bundle == null) { + com.beust.jcommander.ResourceBundle a + = object.getClass().getAnnotation(com.beust.jcommander.ResourceBundle.class); + if (a != null) { + m_bundle = ResourceBundle.getBundle(a.value(), Locale.getDefault()); + } + } - if (m_bundle != null) { - m_description = m_bundle.getString(annotation.descriptionKey()); - } else { - m_description = annotation.description(); + m_description = annotation.description(); + if (! "".equals(annotation.descriptionKey())) { + if (m_bundle != null) { + m_description = m_bundle.getString(annotation.descriptionKey()); + } else { +// System.out.println("Warning: field " + object.getClass() + "." + field.getName() +// + " has a descriptionKey but no bundle was defined with @ResourceBundle, using " + +// "default description:'" + m_description + "'"); + } } } diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java new file mode 100644 index 0000000..789f738 --- /dev/null +++ b/src/main/java/com/beust/jcommander/ResourceBundle.java @@ -0,0 +1,15 @@ +package com.beust.jcommander; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ TYPE }) +public @interface ResourceBundle { + /** + * The name of the resource bundle to use for this class. + */ + String value(); +} -- cgit v1.2.3 From 1d8d7fed4ca7bb1f2d8c318a60b9c46ffef1a506 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Sat, 17 Jul 2010 01:13:38 +0200 Subject: Fix warnings --- src/main/java/com/beust/jcommander/JCommander.java | 11 +++++------ src/main/java/com/beust/jcommander/ParameterDescription.java | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index a14a3e5..bdc36f7 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -88,7 +88,7 @@ public class JCommander { m_objects = Lists.newArrayList(); if (object instanceof Iterable) { // Iterable - for (Object o : (Iterable) object) { + for (Object o : (Iterable) object) { m_objects.add(o); } } else if (object.getClass().isArray()) { @@ -188,12 +188,10 @@ public class JCommander { if (result.startsWith("\"")) { if (result.endsWith("\"")) { return result.substring(1, result.length() - 1); - } else { - return result.substring(1); } - } else { - return result; + return result.substring(1); } + return result; } private void createDescriptions() { @@ -296,6 +294,7 @@ public class JCommander { } try { + @SuppressWarnings("unchecked") List result = (List) m_mainParameterField.get(m_mainParameterObject); if (result == null) { result = Lists.newArrayList(); @@ -328,7 +327,7 @@ public class JCommander { * format (e.g. HTML). */ public List getParameters() { - return new ArrayList(m_fields.values()); + return new ArrayList(m_fields.values()); } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 64bef39..301e376 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -124,7 +124,8 @@ public class ParameterDescription { converter = converterClass.newInstance(); Object convertedValue = converter.convert(value); if (arity) { - List l = (List) m_field.get(m_object); + @SuppressWarnings("unchecked") + List l = (List) m_field.get(m_object); if (l == null) { l = Lists.newArrayList(); m_field.set(m_object, l); -- cgit v1.2.3 From 122e13e253d676b47b23df91f9c5107086ce91ad Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 19:35:49 -0700 Subject: Removed tab --- src/main/java/com/beust/jcommander/ParameterDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 301e376..5dd774b 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -125,7 +125,7 @@ public class ParameterDescription { Object convertedValue = converter.convert(value); if (arity) { @SuppressWarnings("unchecked") - List l = (List) m_field.get(m_object); + List l = (List) m_field.get(m_object); if (l == null) { l = Lists.newArrayList(); m_field.set(m_object, l); -- cgit v1.2.3 From f4af92675def06bbba93e881ae801486224b9b3b Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 16 Jul 2010 20:02:36 -0700 Subject: Removed unused field --- src/main/java/com/beust/jcommander/ParameterDescription.java | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 5dd774b..cd4c4f7 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -32,11 +32,6 @@ public class ParameterDescription { put(boolean.class, BooleanConverter.class); }}; - /** - * A map of converters per field. Will take precedence over the class converter map. - */ - private Map m_fieldConverters = Maps.newHashMap(); - private Object m_object; private Parameter m_parameterAnnotation; private Field m_field; -- cgit v1.2.3 From d3b9e34aed415eba172befec79d2261c3ac38123 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 18 Jul 2010 10:54:24 -0700 Subject: Added arity boolean parameters () --- src/main/java/com/beust/jcommander/JCommander.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bdc36f7..7f62949 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,8 +1,5 @@ package com.beust.jcommander; -import com.beust.jcommander.converters.IntegerConverter; -import com.beust.jcommander.converters.LongConverter; -import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; @@ -13,7 +10,6 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -253,7 +249,8 @@ public class JCommander { pd.addValue(new String(password)); } else { Class fieldType = pd.getField().getType(); - if (fieldType == boolean.class || fieldType == Boolean.class) { + if ((fieldType == boolean.class || fieldType == Boolean.class) + && pd.getParameter().arity() == -1) { pd.addValue("true"); m_requiredFields.remove(pd.getField()); } else { @@ -275,7 +272,7 @@ public class JCommander { } } else { - if (! isStringEmpty(args[i])) getMainParameter().add(args[i]); + if (! isStringEmpty(args[i])) getMainParameter(args[i]).add(args[i]); } } } @@ -286,11 +283,14 @@ public class JCommander { /** * @return the field that's meant to receive all the parameters that are not options. + * + * @param arg the arg that we're about to add (only passed here to ouput a meaningful + * error message). */ - private List getMainParameter() { + private List getMainParameter(String arg) { if (m_mainParameterField == null) { throw new ParameterException( - "Non option parameters were found but no main parameter was defined"); + "Was passed main parameter '" + arg + "' but no main parameter was defined"); } try { -- cgit v1.2.3 From b45c8d8f7af1d808a9073a436e27002edad3b451 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 18 Jul 2010 13:30:26 -0700 Subject: Added traces with -Djcommander.debug=true --- src/main/java/com/beust/jcommander/JCommander.java | 11 +++++++++++ src/main/java/com/beust/jcommander/ParameterDescription.java | 7 +++++++ 2 files changed, 18 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7f62949..07a451a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -27,6 +27,8 @@ import java.util.ResourceBundle; * @author cbeust */ public class JCommander { + public static final String DEBUG_PROPERTY = "jcommander.debug"; + /** * A map to look up parameter description per option name. */ @@ -233,8 +235,11 @@ public class JCommander { } private void parseValues(String[] args) { +// log("Parsing args" + join(args, " "); + for (int i = 0; i < args.length; i++) { String a = trim(args[i]); + log("Parsing arg:" + a); if (a.startsWith("-")) { ParameterDescription pd = m_descriptions.get(a); if (pd != null) { @@ -329,5 +334,11 @@ public class JCommander { public List getParameters() { return new ArrayList(m_fields.values()); } + + private void log(String string) { + if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { + System.out.println("[JCommander] " + string); + } + } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index cd4c4f7..85daf8e 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -96,6 +96,7 @@ public class ParameterDescription { * any type converter, and if we can't find any, throw an exception. */ public void addValue(String value) { + log("Adding value:" + value + " to parameter:" + m_field); boolean arity = false; if (m_added && ! isMultiOption()) { throw new ParameterException("Can only specify option " + getNames()[0] + " once."); @@ -137,4 +138,10 @@ public class ParameterDescription { e.printStackTrace(); } } + + private void log(String string) { + if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { + System.out.println("[ParameterDescription] " + string); + } + } } -- cgit v1.2.3 From 4312bccb3787db4e24d19c16c5786bf2a503a9b9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 20 Jul 2010 22:03:51 -0700 Subject: Throwing ParameterException if bad parameters passed --- src/main/java/com/beust/jcommander/ParameterException.java | 4 ++++ .../java/com/beust/jcommander/converters/IntegerConverter.java | 7 ++++++- src/main/java/com/beust/jcommander/converters/LongConverter.java | 7 ++++++- 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java index 5004cd0..81353bf 100644 --- a/src/main/java/com/beust/jcommander/ParameterException.java +++ b/src/main/java/com/beust/jcommander/ParameterException.java @@ -2,6 +2,10 @@ package com.beust.jcommander; public class ParameterException extends RuntimeException { + public ParameterException(Throwable t) { + super(t); + } + public ParameterException(String string) { super(string); } diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index 2efe058..77c52c2 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -1,12 +1,17 @@ package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.ParameterException; public class IntegerConverter implements IStringConverter { @Override public Integer convert(String value) { - return Integer.parseInt(value); + try { + return Integer.parseInt(value); + } catch(NumberFormatException ex) { + throw new ParameterException(ex); + } } } diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index d14fd23..cc3e9b7 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -1,12 +1,17 @@ package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.ParameterException; public class LongConverter implements IStringConverter { @Override public Long convert(String value) { - return Long.parseLong(value); + try { + return Long.parseLong(value); + } catch(NumberFormatException ex) { + throw new ParameterException(ex); + } } } -- cgit v1.2.3 From 0a0d8099f7e0c2f2f79e6f9233bcfeb7147995e6 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 20 Jul 2010 22:33:08 -0700 Subject: Usage is sorted and aligned --- src/main/java/com/beust/jcommander/JCommander.java | 34 +++++++++++++++++----- .../com/beust/jcommander/ParameterDescription.java | 16 ++++++---- 2 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 07a451a..80fa60c 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -116,7 +118,7 @@ public class JCommander { if (! m_requiredFields.isEmpty()) { StringBuilder missingFields = new StringBuilder(); for (ParameterDescription pd : m_requiredFields.values()) { - missingFields.append(pd.getNames()[0]).append(" "); + missingFields.append(pd.getNames()).append(" "); } throw new ParameterException("The following options are required: " + missingFields); } @@ -246,10 +248,9 @@ public class JCommander { if (pd.getParameter().password()) { Console console = System.console(); if (console == null) { - throw new ParameterException("No console is available to get parameter " - + pd.getNames()[0]); + throw new ParameterException("No console is available to get parameter " + a); } - System.out.print("Value for " + pd.getNames()[0] + " (" + pd.getDescription() + "):"); + System.out.print("Value for " + a + " (" + pd.getDescription() + "):"); char[] password = console.readPassword(); pd.addValue(new String(password)); } else { @@ -317,12 +318,29 @@ public class JCommander { */ public void usage() { System.out.println("Usage:"); + int longestName = 0; + List sorted = Lists.newArrayList(); for (ParameterDescription pd : m_fields.values()) { - StringBuilder sb = new StringBuilder(); - for (String n : pd.getParameter().names()) { - sb.append(n).append(" "); + sorted.add(pd); + int length = pd.getNames().length(); + if (length > longestName) { + longestName = length; } - System.out.println("\t" + sb.toString() + "\t" + pd.getDescription()); + } + int target = longestName %8 != 0 ? (((longestName + 8) / 8) * 8): longestName; + Collections.sort(sorted, new Comparator() { + @Override + public int compare(ParameterDescription arg0, ParameterDescription arg1) { + return arg0.getNames().compareTo(arg1.getNames()); + } + }); + + for (ParameterDescription pd : sorted) { + int l = target - pd.getNames().length(); + int tabCount = l / 8 + (l % 8 == 0 ? 0 : 1); + StringBuilder tabs = new StringBuilder(); + for (int i = 0; i < tabCount; i++) tabs.append("\t"); + System.out.println("\t" + pd.getNames() + tabs + pd.getDescription()); } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 85daf8e..b1aea92 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -70,14 +70,19 @@ public class ParameterDescription { } } - public String[] getNames() { - return m_parameterAnnotation.names(); - } - public String getDescription() { return m_description; } + public String getNames() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < m_parameterAnnotation.names().length; i++) { + if (i > 0) sb.append(", "); + sb.append(m_parameterAnnotation.names()[i]); + } + return sb.toString(); + } + public Parameter getParameter() { return m_parameterAnnotation; } @@ -99,7 +104,8 @@ public class ParameterDescription { log("Adding value:" + value + " to parameter:" + m_field); boolean arity = false; if (m_added && ! isMultiOption()) { - throw new ParameterException("Can only specify option " + getNames()[0] + " once."); + throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + + " once."); } Class converterClass = m_parameterAnnotation.converter(); if (converterClass == NoConverter.class) { -- cgit v1.2.3 From b10564134cd6e95603198fdb0d910af839f79c6a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 20 Jul 2010 23:11:25 -0700 Subject: Added hidden --- src/main/java/com/beust/jcommander/JCommander.java | 10 ++++++---- src/main/java/com/beust/jcommander/Parameter.java | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 80fa60c..09ea6ed 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -321,10 +321,12 @@ public class JCommander { int longestName = 0; List sorted = Lists.newArrayList(); for (ParameterDescription pd : m_fields.values()) { - sorted.add(pd); - int length = pd.getNames().length(); - if (length > longestName) { - longestName = length; + if (! pd.getParameter().hidden()) { + sorted.add(pd); + int length = pd.getNames().length(); + if (length > longestName) { + longestName = length; + } } } int target = longestName %8 != 0 ? (((longestName + 8) / 8) * 8): longestName; diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 9d4ef62..462a526 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -45,5 +45,13 @@ public @interface Parameter { */ boolean password() default false; + /** + * The string converter to use for this field. + */ Class converter() default NoConverter.class; + + /** + * If true, this parameter won't appear in the usage(). + */ + boolean hidden() default false; } -- cgit v1.2.3 From 010076fc59e6304034a2294ddae646542b2fbbd1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 20 Jul 2010 23:23:32 -0700 Subject: Better error messages --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- src/main/java/com/beust/jcommander/converters/IntegerConverter.java | 2 +- src/main/java/com/beust/jcommander/converters/LongConverter.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 09ea6ed..be2983c 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -100,13 +100,14 @@ public class JCommander { // Single object m_objects.add(object); } + + createDescriptions(); } /** * Parse the command line parameters. */ public void parse(String... args) { - createDescriptions(); parseValues(expandArgs(args)); validateOptions(); } diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index 77c52c2..0be0b5d 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -10,7 +10,7 @@ public class IntegerConverter implements IStringConverter { try { return Integer.parseInt(value); } catch(NumberFormatException ex) { - throw new ParameterException(ex); + throw new ParameterException("Couldn't convert \"" + value + "\" to an integer"); } } diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index cc3e9b7..c785fbc 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -10,7 +10,7 @@ public class LongConverter implements IStringConverter { try { return Long.parseLong(value); } catch(NumberFormatException ex) { - throw new ParameterException(ex); + throw new ParameterException("Couldn't convert \"" + value + "\" to a long"); } } -- cgit v1.2.3 From 2bf18b767712ce3b24df4be60bc341381432dddd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 21 Jul 2010 17:04:37 -0700 Subject: Inserted a space after description usages --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index be2983c..08467b3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -324,7 +324,7 @@ public class JCommander { for (ParameterDescription pd : m_fields.values()) { if (! pd.getParameter().hidden()) { sorted.add(pd); - int length = pd.getNames().length(); + int length = pd.getNames().length() + 1; if (length > longestName) { longestName = length; } -- cgit v1.2.3 From 76c4b6ace154f18794f9eb0c3d6211101bf426d0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 21 Jul 2010 19:05:53 -0700 Subject: Including the option name in the conversion error message --- src/main/java/com/beust/jcommander/Parameter.java | 2 +- .../com/beust/jcommander/ParameterDescription.java | 38 +++++++++++++++++++--- .../beust/jcommander/converters/BaseConverter.java | 21 ++++++++++++ .../jcommander/converters/BooleanConverter.java | 14 ++++++-- .../jcommander/converters/IntegerConverter.java | 9 +++-- .../beust/jcommander/converters/LongConverter.java | 9 +++-- 6 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/converters/BaseConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 462a526..741dbf5 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -48,7 +48,7 @@ public @interface Parameter { /** * The string converter to use for this field. */ - Class converter() default NoConverter.class; + Class> converter() default NoConverter.class; /** * If true, this parameter won't appear in the usage(). diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index b1aea92..6a48a9b 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -7,9 +7,11 @@ import com.beust.jcommander.converters.LongConverter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -21,7 +23,7 @@ public class ParameterDescription { /** * A map of converters per class. */ - private static Map, Class> m_classConverters + private static Map, Class>> m_classConverters = new HashMap() {{ put(String.class, StringConverter.class); put(Integer.class, IntegerConverter.class); @@ -107,7 +109,7 @@ public class ParameterDescription { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + " once."); } - Class converterClass = m_parameterAnnotation.converter(); + Class> converterClass = m_parameterAnnotation.converter(); if (converterClass == NoConverter.class) { converterClass = m_classConverters.get(m_field.getType()); } @@ -121,9 +123,9 @@ public class ParameterDescription { } m_added = true; - IStringConverter converter; + IStringConverter converter; try { - converter = converterClass.newInstance(); + converter = instantiateConverter(converterClass); Object convertedValue = converter.convert(value); if (arity) { @SuppressWarnings("unchecked") @@ -136,6 +138,8 @@ public class ParameterDescription { } else { m_field.set(m_object, convertedValue); } + } catch (InvocationTargetException e) { + e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -145,6 +149,30 @@ public class ParameterDescription { } } + private IStringConverter instantiateConverter( + Class> converterClass) + throws IllegalArgumentException, InstantiationException, IllegalAccessException, + InvocationTargetException { + Constructor> ctor = null; + Constructor> stringCtor = null; + Constructor>[] ctors + = (Constructor>[]) converterClass.getDeclaredConstructors(); + for (Constructor> c : ctors) { + Class[] types = c.getParameterTypes(); + if (types.length == 1 && types[0].equals(String.class)) { + stringCtor = c; + } else if (types.length == 0) { + ctor = c; + } + } + + IStringConverter result = stringCtor != null + ? stringCtor.newInstance(m_parameterAnnotation.names()[0]) + : ctor.newInstance(); + + return result; + } + private void log(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[ParameterDescription] " + string); diff --git a/src/main/java/com/beust/jcommander/converters/BaseConverter.java b/src/main/java/com/beust/jcommander/converters/BaseConverter.java new file mode 100644 index 0000000..94ceaf8 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/BaseConverter.java @@ -0,0 +1,21 @@ +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +abstract public class BaseConverter implements IStringConverter { + + private String m_optionName; + + public BaseConverter(String optionName) { + m_optionName = optionName; + } + + public String getOptionName() { + return m_optionName; + } + + protected String getErrorString(String value, String to) { + return "\"" + getOptionName() + "\": couldn't convert \"" + value + "\" to " + to; + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java index 52cd74c..30fdf1a 100644 --- a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java @@ -1,12 +1,20 @@ package com.beust.jcommander.converters; -import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.ParameterException; -public class BooleanConverter implements IStringConverter { +public class BooleanConverter extends BaseConverter { + + public BooleanConverter(String optionName) { + super(optionName); + } @Override public Boolean convert(String value) { - return Boolean.parseBoolean(value); + if ("false".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)) { + return Boolean.parseBoolean(value); + } else { + throw new ParameterException(getErrorString(value, "a boolean")); + } } } diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index 0be0b5d..4fdf77e 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -1,16 +1,19 @@ package com.beust.jcommander.converters; -import com.beust.jcommander.IStringConverter; import com.beust.jcommander.ParameterException; -public class IntegerConverter implements IStringConverter { +public class IntegerConverter extends BaseConverter { + + public IntegerConverter(String optionName) { + super(optionName); + } @Override public Integer convert(String value) { try { return Integer.parseInt(value); } catch(NumberFormatException ex) { - throw new ParameterException("Couldn't convert \"" + value + "\" to an integer"); + throw new ParameterException(getErrorString(value, "an integer")); } } diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index c785fbc..b3cec97 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -1,16 +1,19 @@ package com.beust.jcommander.converters; -import com.beust.jcommander.IStringConverter; import com.beust.jcommander.ParameterException; -public class LongConverter implements IStringConverter { +public class LongConverter extends BaseConverter { + + public LongConverter(String optionName) { + super(optionName); + } @Override public Long convert(String value) { try { return Long.parseLong(value); } catch(NumberFormatException ex) { - throw new ParameterException("Couldn't convert \"" + value + "\" to a long"); + throw new ParameterException(getErrorString(value, "a long")); } } -- cgit v1.2.3 From 07fd8c45f06c52a2de0d8f60d43b86c57d377631 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 21 Jul 2010 19:17:03 -0700 Subject: Minor fix by Todd Quessenberry --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 08467b3..70d0a52 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -270,7 +270,7 @@ public class JCommander { } i += n; } else { - throw new ParameterException(arity + " parameters expected after " + args[i]); + throw new ParameterException(n + " parameters expected after " + args[i]); } } } -- cgit v1.2.3 From 1a5a124a6c78c9e14fc3b3d027cc0c303e5cd241 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 21 Jul 2010 20:04:09 -0700 Subject: Added Javadoc --- src/main/java/com/beust/jcommander/IStringConverter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IStringConverter.java b/src/main/java/com/beust/jcommander/IStringConverter.java index 9abd96c..53cd35f 100644 --- a/src/main/java/com/beust/jcommander/IStringConverter.java +++ b/src/main/java/com/beust/jcommander/IStringConverter.java @@ -3,8 +3,19 @@ package com.beust.jcommander; /** * An interface that converts strings to any arbitrary type. * + * If your class implements a constructor that takes a String, this + * constructor will be used to instantiate your converter and the + * parameter will receive the name of the option that's being parsed, + * which can be useful to issue a more useful error message if the + * conversion fails. + * + * You can also extend BaseConverter to make your life easier. + * * @author cbeust */ public interface IStringConverter { + /** + * @return an object of type created from the parameter value. + */ T convert(String value); } -- cgit v1.2.3 From 116f9d2fd1500980bbd36255020bfce5b1deb84a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 21 Jul 2010 21:39:47 -0700 Subject: Minor fixes --- src/main/java/com/beust/jcommander/JCommander.java | 43 +++++++++++++++------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 70d0a52..4cdf0c8 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -153,7 +153,7 @@ public class JCommander { /** * Reads the file specified by filename and returns the file content as a string. - * End of lines are replaced by a space + * End of lines are replaced by a space. * * @param fileName the command line filename * @return the file content as a string. @@ -181,8 +181,7 @@ public class JCommander { } /** - * @param string - * @return + * Remove spaces at both ends and handle double quotes. */ private static String trim(String string) { String result = string.trim(); @@ -195,6 +194,9 @@ public class JCommander { return result; } + /** + * Create the ParameterDescriptions for all the @Parameter found. + */ private void createDescriptions() { m_descriptions = Maps.newHashMap(); @@ -231,22 +233,20 @@ public class JCommander { } } - private void p(String string) { - if (false) { - System.out.println("[JCommander] " + string); - } - } - + /** + * Main method that parses the values and initializes the fields accordingly. + */ private void parseValues(String[] args) { -// log("Parsing args" + join(args, " "); - for (int i = 0; i < args.length; i++) { String a = trim(args[i]); - log("Parsing arg:" + a); + p("Parsing arg:" + a); if (a.startsWith("-")) { ParameterDescription pd = m_descriptions.get(a); if (pd != null) { if (pd.getParameter().password()) { + // + // Password option, use the Console to retrieve the password + // Console console = System.console(); if (console == null) { throw new ParameterException("No console is available to get parameter " + a); @@ -255,12 +255,20 @@ public class JCommander { char[] password = console.readPassword(); pd.addValue(new String(password)); } else { + // + // Regular option + // Class fieldType = pd.getField().getType(); + + // Boolean, set to true as soon as we see it, unless it specified + // an arity of 1, in which case we need to read the next value if ((fieldType == boolean.class || fieldType == Boolean.class) && pd.getParameter().arity() == -1) { pd.addValue("true"); m_requiredFields.remove(pd.getField()); } else { + // Regular parameter, use the arity to tell use how many values + // we need to consume int arity = pd.getParameter().arity(); int n = (arity != -1 ? arity : 1); if (i + n < args.length) { @@ -319,17 +327,23 @@ public class JCommander { */ public void usage() { System.out.println("Usage:"); + + // Will contain the size of the longest option name int longestName = 0; List sorted = Lists.newArrayList(); for (ParameterDescription pd : m_fields.values()) { if (! pd.getParameter().hidden()) { sorted.add(pd); + // +1 to have an extra space between the name and the description int length = pd.getNames().length() + 1; if (length > longestName) { longestName = length; } } } + + // Calculate the tab stop at which all the descriptions should be + // aligned based on the longest option name found. int target = longestName %8 != 0 ? (((longestName + 8) / 8) * 8): longestName; Collections.sort(sorted, new Comparator() { @Override @@ -337,7 +351,8 @@ public class JCommander { return arg0.getNames().compareTo(arg1.getNames()); } }); - + + // Display all the names and descriptions at the right tab position for (ParameterDescription pd : sorted) { int l = target - pd.getNames().length(); int tabCount = l / 8 + (l % 8 == 0 ? 0 : 1); @@ -356,7 +371,7 @@ public class JCommander { return new ArrayList(m_fields.values()); } - private void log(String string) { + private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[JCommander] " + string); } -- cgit v1.2.3 From b2b58d4e3845c1eaa85d7a63cf4632f58e634056 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 22 Jul 2010 09:23:00 -0700 Subject: Fixed List bug --- src/main/java/com/beust/jcommander/JCommander.java | 15 +++++++++++++-- .../java/com/beust/jcommander/ParameterDescription.java | 12 ++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 4cdf0c8..275ae6b 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -52,6 +52,11 @@ public class JCommander { */ private Object m_mainParameterObject; + /** + * The annotation found on the main parameter field. + */ + private Parameter m_mainParameterAnnotation; + /** * A set of all the fields that are required. During the reflection phase, * this field receives all the fields that are annotated with required=true @@ -216,6 +221,7 @@ public class JCommander { } m_mainParameterField = f; m_mainParameterObject = object; + m_mainParameterAnnotation = p; } else { for (String name : p.names()) { if (m_descriptions.containsKey(name)) { @@ -326,7 +332,12 @@ public class JCommander { * Display a the help on System.out. */ public void usage() { - System.out.println("Usage:"); + StringBuilder sb = new StringBuilder("Usage:
[options]"); + if (m_mainParameterAnnotation != null) { + sb.append(" " + m_mainParameterAnnotation.description()); + } + sb.append("\n Options:"); + System.out.println(sb.toString()); // Will contain the size of the longest option name int longestName = 0; @@ -358,7 +369,7 @@ public class JCommander { int tabCount = l / 8 + (l % 8 == 0 ? 0 : 1); StringBuilder tabs = new StringBuilder(); for (int i = 0; i < tabCount; i++) tabs.append("\t"); - System.out.println("\t" + pd.getNames() + tabs + pd.getDescription()); + System.out.println(" " + pd.getNames() + tabs + pd.getDescription()); } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 6a48a9b..9493d81 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -11,7 +11,7 @@ import com.beust.jcommander.internal.Lists; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.TypeVariable; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -104,7 +104,7 @@ public class ParameterDescription { */ public void addValue(String value) { log("Adding value:" + value + " to parameter:" + m_field); - boolean arity = false; + boolean isCollection = false; if (m_added && ! isMultiOption()) { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + " once."); @@ -115,7 +115,11 @@ public class ParameterDescription { } if (converterClass == null && m_parameterAnnotation.arity() >= 2) { converterClass = StringConverter.class; - arity = true; + isCollection = true; + } + if (converterClass == null && Collection.class.isAssignableFrom(m_field.getType())) { + converterClass = StringConverter.class; + isCollection = true; } if (converterClass == null) { throw new ParameterException("Don't know how to convert " + value @@ -127,7 +131,7 @@ public class ParameterDescription { try { converter = instantiateConverter(converterClass); Object convertedValue = converter.convert(value); - if (arity) { + if (isCollection) { @SuppressWarnings("unchecked") List l = (List) m_field.get(m_object); if (l == null) { -- cgit v1.2.3 From b8010b01b766d131076f7343be5e36e7014319e3 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 23 Jul 2010 10:17:48 -0700 Subject: Introduced @Parameters, moved resourceBundle there --- .../com/beust/jcommander/ParameterDescription.java | 28 ++++++++++++++++++---- .../java/com/beust/jcommander/ResourceBundle.java | 5 ++++ 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 9493d81..1f1746d 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -47,17 +47,35 @@ public class ParameterDescription { init(object, annotation, field, bundle); } + /** + * Find the resource bundle in the annotations. + * @return + */ + private ResourceBundle findResourceBundle(Object o) { + ResourceBundle result = null; + + Parameters p = o.getClass().getAnnotation(Parameters.class); + if (p != null) { + result = ResourceBundle.getBundle(p.resourceBundle(), Locale.getDefault()); + } + else { + com.beust.jcommander.ResourceBundle a = o.getClass().getAnnotation( + com.beust.jcommander.ResourceBundle.class); + if (a != null) { + result = ResourceBundle.getBundle(a.value(), Locale.getDefault()); + } + } + + return result; + } + private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle) { m_object = object; m_parameterAnnotation = annotation; m_field = field; m_bundle = bundle; if (m_bundle == null) { - com.beust.jcommander.ResourceBundle a - = object.getClass().getAnnotation(com.beust.jcommander.ResourceBundle.class); - if (a != null) { - m_bundle = ResourceBundle.getBundle(a.value(), Locale.getDefault()); - } + m_bundle = findResourceBundle(object); } m_description = annotation.description(); diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java index 789f738..94df0ae 100644 --- a/src/main/java/com/beust/jcommander/ResourceBundle.java +++ b/src/main/java/com/beust/jcommander/ResourceBundle.java @@ -5,6 +5,11 @@ import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.Target; +/** + * @deprecated, use @Parameters + * + * @author cbeust + */ @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({ TYPE }) public @interface ResourceBundle { -- cgit v1.2.3 From 133eecf3498f32ddcfc0930c0b07dd30c702410d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 23 Jul 2010 10:19:03 -0700 Subject: Forgot files --- src/main/java/com/beust/jcommander/Parameters.java | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/Parameters.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java new file mode 100644 index 0000000..1feb224 --- /dev/null +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -0,0 +1,26 @@ +package com.beust.jcommander; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * An annotation used to specify settings for parameter parsing. + * + * @author cbeust + */ +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ TYPE }) +public @interface Parameters { + + /** + * The name of the resource bundle to use for this class. + */ + String resourceBundle() default ""; + + /** + * The character(s) that separate options. + */ + String separators() default " "; +} -- cgit v1.2.3 From 85866a95d6479be731596a838b6f5e793a341f5b Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 23 Jul 2010 11:19:54 -0700 Subject: First pass at implementing separators --- src/main/java/com/beust/jcommander/JCommander.java | 57 +++++++++++++++++++--- .../com/beust/jcommander/ParameterDescription.java | 15 ++++-- 2 files changed, 61 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 275ae6b..0fe79b4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -139,21 +139,64 @@ public class JCommander { * @param originalArgv the original command line parameters * @return the new and enriched command line parameters */ - private static String[] expandArgs(String[] originalArgv) { - List vResult = Lists.newArrayList(); - + private String[] expandArgs(String[] originalArgv) { + List vResult1 = Lists.newArrayList(); + + // + // Expand @ + // for (String arg : originalArgv) { if (arg.startsWith("@")) { String fileName = arg.substring(1); - vResult.addAll(readFile(fileName)); + vResult1.addAll(readFile(fileName)); } else { - vResult.add(arg); + vResult1.add(arg); } } - - return vResult.toArray(new String[vResult.size()]); + + // + // Expand separators + // + List vResult2 = Lists.newArrayList(); + for (int i = 0; i < vResult1.size(); i++) { + String arg = vResult1.get(i); + // TODO: make sure it's really an option and not that it starts with "-" + if (arg.startsWith("-")) { + String sep = getSeparatorFor(arg); + if (! " ".equals(sep)) { + String[] sp = arg.split(sep); + for (String ssp : sp) { + vResult2.add(ssp); + } + } else { + vResult2.add(arg); + } + } else { + vResult2.add(arg); + } + } + + return vResult2.toArray(new String[vResult2.size()]); + } + + private ParameterDescription getDescriptionFor(String arg) { + for (ParameterDescription p : m_descriptions.values()) { + for (String n : p.getParameter().names()) { + if (arg.startsWith(n)) { + return p; + } + } + } + throw new ParameterException("Couldn't find a description for " + arg); + } + + private String getSeparatorFor(String arg) { + ParameterDescription pd = getDescriptionFor(arg); + Parameters p = pd.getObject().getClass().getAnnotation(Parameters.class); + if (p != null) return p.separators(); + else return " "; } /** diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 1f1746d..f990208 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -55,13 +55,12 @@ public class ParameterDescription { ResourceBundle result = null; Parameters p = o.getClass().getAnnotation(Parameters.class); - if (p != null) { + if (p != null && ! isEmpty(p.resourceBundle())) { result = ResourceBundle.getBundle(p.resourceBundle(), Locale.getDefault()); - } - else { + } else { com.beust.jcommander.ResourceBundle a = o.getClass().getAnnotation( com.beust.jcommander.ResourceBundle.class); - if (a != null) { + if (a != null && ! isEmpty(a.value())) { result = ResourceBundle.getBundle(a.value(), Locale.getDefault()); } } @@ -69,6 +68,10 @@ public class ParameterDescription { return result; } + private boolean isEmpty(String s) { + return s == null || "".equals(s); + } + private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle) { m_object = object; m_parameterAnnotation = annotation; @@ -94,6 +97,10 @@ public class ParameterDescription { return m_description; } + public Object getObject() { + return m_object; + } + public String getNames() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < m_parameterAnnotation.names().length; i++) { -- cgit v1.2.3 From fe9b1e59d132e6b10819ae8c9dc3300fb3200ae0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 23 Jul 2010 15:18:22 -0700 Subject: More tests --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0fe79b4..4b7b621 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -166,7 +166,7 @@ public class JCommander { if (arg.startsWith("-")) { String sep = getSeparatorFor(arg); if (! " ".equals(sep)) { - String[] sp = arg.split(sep); + String[] sp = arg.split("[" + sep + "]"); for (String ssp : sp) { vResult2.add(ssp); } -- cgit v1.2.3 From e78248b969b0fa0f217ce85e43d39a1d7c055753 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 24 Jul 2010 14:29:56 -0700 Subject: 1.3 --- src/main/java/com/beust/jcommander/JCommander.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 4b7b621..b32e293 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -388,30 +388,27 @@ public class JCommander { for (ParameterDescription pd : m_fields.values()) { if (! pd.getParameter().hidden()) { sorted.add(pd); - // +1 to have an extra space between the name and the description - int length = pd.getNames().length() + 1; + // + to have an extra space between the name and the description + int length = pd.getNames().length() + 2; if (length > longestName) { longestName = length; } } } - // Calculate the tab stop at which all the descriptions should be - // aligned based on the longest option name found. - int target = longestName %8 != 0 ? (((longestName + 8) / 8) * 8): longestName; Collections.sort(sorted, new Comparator() { @Override public int compare(ParameterDescription arg0, ParameterDescription arg1) { - return arg0.getNames().compareTo(arg1.getNames()); + return arg0.getNames().toLowerCase().compareTo(arg1.getNames().toLowerCase()); } }); // Display all the names and descriptions at the right tab position for (ParameterDescription pd : sorted) { - int l = target - pd.getNames().length(); - int tabCount = l / 8 + (l % 8 == 0 ? 0 : 1); + int l = pd.getNames().length(); + int spaceCount = longestName - l; StringBuilder tabs = new StringBuilder(); - for (int i = 0; i < tabCount; i++) tabs.append("\t"); + for (int i = 0; i < spaceCount; i++) tabs.append(" "); System.out.println(" " + pd.getNames() + tabs + pd.getDescription()); } } -- cgit v1.2.3 From 78fcfb77f843f4636b50d40f69ce60cb0c2ae7bd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 26 Jul 2010 22:15:02 -0700 Subject: Support for IDefaultProvider --- .../com/beust/jcommander/IDefaultProvider.java | 17 +++++++++++++ src/main/java/com/beust/jcommander/JCommander.java | 28 ++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IDefaultProvider.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IDefaultProvider.java b/src/main/java/com/beust/jcommander/IDefaultProvider.java new file mode 100644 index 0000000..5ea0bc1 --- /dev/null +++ b/src/main/java/com/beust/jcommander/IDefaultProvider.java @@ -0,0 +1,17 @@ +package com.beust.jcommander; + +/** + * Allows the specification of default values. + * + * @author cbeust + */ +public interface IDefaultProvider { + + /** + * @param optionName The name of the option as specified in the names() attribute + * of the @Parameter option (e.g. "-file"). + * + * @return the default value for this option. + */ + String getDefaultValueFor(String optionName); +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b32e293..7c95d32 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -74,6 +74,8 @@ public class JCommander { private ResourceBundle m_bundle; + private IDefaultProvider m_defaultProvider; + public JCommander(Object object) { init(object, null); } @@ -189,7 +191,7 @@ public class JCommander { } } } - throw new ParameterException("Couldn't find a description for " + arg); + throw new ParameterException("Unknown parameter: " + arg); } private String getSeparatorFor(String arg) { @@ -206,7 +208,7 @@ public class JCommander { * @param fileName the command line filename * @return the file content as a string. */ - public static List readFile(String fileName) { + private static List readFile(String fileName) { List result = Lists.newArrayList(); try { @@ -274,6 +276,7 @@ public class JCommander { ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle); m_fields.put(f, pd); m_descriptions.put(name, pd); + if (p.required()) m_requiredFields.put(f, pd); } } @@ -282,6 +285,15 @@ public class JCommander { } } + private void initializeDefaultValue(ParameterDescription pd) { + String optionName = pd.getParameter().names()[0]; + String def = m_defaultProvider.getDefaultValueFor(optionName); + if (def != null) { + p("Initializing " + optionName + " with default value:" + def); + pd.addValue(def); + } + } + /** * Main method that parses the values and initializes the fields accordingly. */ @@ -427,5 +439,17 @@ public class JCommander { System.out.println("[JCommander] " + string); } } + + /** + * Define the default provider for this instance. + */ + public void setDefaultProvider(IDefaultProvider defaultProvider) { + m_defaultProvider = defaultProvider; + if (m_defaultProvider != null) { + for (ParameterDescription pd : m_descriptions.values()) { + initializeDefaultValue(pd); + } + } + } } -- cgit v1.2.3 From 35435b045d8f218d0202c53ea76e316442c6eccc Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 26 Jul 2010 22:25:36 -0700 Subject: More tests for default providers --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- .../java/com/beust/jcommander/ParameterDescription.java | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7c95d32..16ec4f6 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -290,7 +290,7 @@ public class JCommander { String def = m_defaultProvider.getDefaultValueFor(optionName); if (def != null) { p("Initializing " + optionName + " with default value:" + def); - pd.addValue(def); + pd.addValue(def, false /* don't mark as assigned */); } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index f990208..007c3bb 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -38,7 +38,7 @@ public class ParameterDescription { private Parameter m_parameterAnnotation; private Field m_field; /** Keep track of whether a value was added to flag an error */ - private boolean m_added = false; + private boolean m_assigned = false; private ResourceBundle m_bundle; private String m_description; @@ -123,14 +123,20 @@ public class ParameterDescription { return fieldType.equals(List.class) || fieldType.equals(Set.class); } + public void addValue(String value) { + addValue(value, true /* mark as assigned */); + } + /** * Add the specified value to the field. First look up any field converter, then * any type converter, and if we can't find any, throw an exception. + * + * @param markAdded if true, mark this parameter as assigned */ - public void addValue(String value) { + public void addValue(String value, boolean markAssigned) { log("Adding value:" + value + " to parameter:" + m_field); boolean isCollection = false; - if (m_added && ! isMultiOption()) { + if (m_assigned && ! isMultiOption()) { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + " once."); } @@ -151,7 +157,8 @@ public class ParameterDescription { + " to type " + m_field.getType() + " (field: " + m_field.getName() + ")"); } - m_added = true; + if (markAssigned) m_assigned = true; + IStringConverter converter; try { converter = instantiateConverter(converterClass); -- cgit v1.2.3 From eca9dc8ab293c10f16a104e107b402b61c4c76de Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 27 Jul 2010 07:44:31 -0700 Subject: Added PropertyFileDefaultProvider --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- .../com/beust/jcommander/ParameterDescription.java | 9 ++-- .../PropertyFileDefaultProvider.java | 53 ++++++++++++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 16ec4f6..1619e62 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -290,7 +290,7 @@ public class JCommander { String def = m_defaultProvider.getDefaultValueFor(optionName); if (def != null) { p("Initializing " + optionName + " with default value:" + def); - pd.addValue(def, false /* don't mark as assigned */); + pd.addValue(def, true /* default */); } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 007c3bb..69a87f1 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -124,7 +124,7 @@ public class ParameterDescription { } public void addValue(String value) { - addValue(value, true /* mark as assigned */); + addValue(value, false /* not default */); } /** @@ -133,8 +133,9 @@ public class ParameterDescription { * * @param markAdded if true, mark this parameter as assigned */ - public void addValue(String value, boolean markAssigned) { - log("Adding value:" + value + " to parameter:" + m_field); + public void addValue(String value, boolean isDefault) { + log("Adding " + (isDefault ? "default " : "") + "value:" + value + + " to parameter:" + m_field.getName()); boolean isCollection = false; if (m_assigned && ! isMultiOption()) { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] @@ -157,7 +158,7 @@ public class ParameterDescription { + " to type " + m_field.getType() + " (field: " + m_field.getName() + ")"); } - if (markAssigned) m_assigned = true; + if (! isDefault) m_assigned = true; IStringConverter converter; try { diff --git a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java new file mode 100644 index 0000000..50f33a4 --- /dev/null +++ b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java @@ -0,0 +1,53 @@ +package com.beust.jcommander.defaultprovider; + +import com.beust.jcommander.IDefaultProvider; +import com.beust.jcommander.ParameterException; + +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +/** + * A default provider that reads its default values from a property file. + * + * @author cbeust + */ +public class PropertyFileDefaultProvider implements IDefaultProvider { + public static final String DEFAULT_FILE_NAME = "jcommander.properties"; + private Properties m_properties; + + public PropertyFileDefaultProvider() { + init(DEFAULT_FILE_NAME); + } + + public PropertyFileDefaultProvider(String fileName) { + init(fileName); + } + + private void init(String fileName) { + try { + m_properties = new Properties(); + URL url = ClassLoader.getSystemResource(fileName); + if (url != null) { + m_properties.load(url.openStream()); + } else { + throw new ParameterException("Could not find property file: " + fileName + + " on the class path"); + } + } + catch (IOException e) { + throw new ParameterException("Could not open property file: " + fileName); + } + } + + @Override + public String getDefaultValueFor(String optionName) { + int index = 0; + while (index < optionName.length() && ! Character.isLetterOrDigit(optionName.charAt(index))) { + index++; + } + String key = optionName.substring(index); + return m_properties.getProperty(key); + } + +} -- cgit v1.2.3 From 5f57e62a9aad979f2fe17e6d61ce5d05136661db Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 27 Jul 2010 15:02:56 -0700 Subject: Added support for -- --- src/main/java/com/beust/jcommander/JCommander.java | 65 +++++++++++++++++----- .../com/beust/jcommander/ParameterDescription.java | 6 ++ 2 files changed, 58 insertions(+), 13 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1619e62..0026d0a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -165,15 +165,20 @@ public class JCommander { for (int i = 0; i < vResult1.size(); i++) { String arg = vResult1.get(i); // TODO: make sure it's really an option and not that it starts with "-" - if (arg.startsWith("-")) { - String sep = getSeparatorFor(arg); - if (! " ".equals(sep)) { - String[] sp = arg.split("[" + sep + "]"); - for (String ssp : sp) { - vResult2.add(ssp); - } - } else { + if (isOption(arg)) { + if ("--".equals(arg)) { vResult2.add(arg); + vResult2.add(vResult1.get(++i)); + } else { + String sep = getSeparatorFor(arg); + if (! " ".equals(sep)) { + String[] sp = arg.split("[" + sep + "]"); + for (String ssp : sp) { + vResult2.add(ssp); + } + } else { + vResult2.add(arg); + } } } else { vResult2.add(arg); @@ -183,6 +188,10 @@ public class JCommander { return vResult2.toArray(new String[vResult2.size()]); } + private boolean isOption(String arg) { + return arg.startsWith("-"); + } + private ParameterDescription getDescriptionFor(String arg) { for (ParameterDescription p : m_descriptions.values()) { for (String n : p.getParameter().names()) { @@ -301,8 +310,35 @@ public class JCommander { for (int i = 0; i < args.length; i++) { String a = trim(args[i]); p("Parsing arg:" + a); - if (a.startsWith("-")) { - ParameterDescription pd = m_descriptions.get(a); +// ParameterDescription previousDescription = null; + + if (isOption(a)) { + ParameterDescription pd = m_descriptions.get(a); +// ParameterDescription pd = null; +// +// if ("--".equals(a)) { +// pd = previousDescription; +// i++; +// } else { +// } +// previousDescription = pd; + + // If we don't find any description, see if the previous parameter is an int + // or a long, and if it is, check to see if the current arg can be parsed + // into a negative integer +// if (pd == null && pd.isNumber()) { +// try { +// Long l = Long.parseLong(a); +// pd = previousDescription; +// i--; +// } +// catch(NumberFormatException ex) { +// // Do nothing, we'll fall through and throw a parameter exception +// } +// } +// +// previousDescription = pd; + if (pd != null) { if (pd.getParameter().password()) { // @@ -331,13 +367,16 @@ public class JCommander { // Regular parameter, use the arity to tell use how many values // we need to consume int arity = pd.getParameter().arity(); - int n = (arity != -1 ? arity : 1); + int n = (arity != -1 ? arity : 1); + + int offset = "--".equals(args[i + 1]) ? 1 : 0; + if (i + n < args.length) { for (int j = 1; j <= n; j++) { - pd.addValue(trim(args[i + j])); + pd.addValue(trim(args[i + j + offset])); m_requiredFields.remove(pd.getField()); } - i += n; + i += n + offset; } else { throw new ParameterException(n + " parameters expected after " + args[i]); } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 69a87f1..a15f643 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -186,6 +186,12 @@ public class ParameterDescription { } } + public boolean isNumber() { + Class type = m_field.getType(); + return type.equals(Integer.class) || type.equals(int.class) + || type.equals(Long.class) || type.equals(long.class); + } + private IStringConverter instantiateConverter( Class> converterClass) throws IllegalArgumentException, InstantiationException, IllegalAccessException, -- cgit v1.2.3 From 7e185fed573b35ea0769f59348e640514da392b0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 27 Jul 2010 22:26:37 -0700 Subject: Showing required parameters in usage --- src/main/java/com/beust/jcommander/JCommander.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1619e62..b9c912d 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -421,7 +421,9 @@ public class JCommander { int spaceCount = longestName - l; StringBuilder tabs = new StringBuilder(); for (int i = 0; i < spaceCount; i++) tabs.append(" "); - System.out.println(" " + pd.getNames() + tabs + pd.getDescription()); + System.out.println(" " + + (pd.getParameter().required() ? "* " : " ") + + pd.getNames() + tabs + pd.getDescription()); } } -- cgit v1.2.3 From ff21d677513a8fc628476d926a7f9c7a6dec9570 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 27 Jul 2010 22:41:00 -0700 Subject: Usage is now showing required parameters and default value --- src/main/java/com/beust/jcommander/JCommander.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index ee45111..e36e120 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -455,15 +455,27 @@ public class JCommander { }); // Display all the names and descriptions at the right tab position + StringBuilder out = new StringBuilder(); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; StringBuilder tabs = new StringBuilder(); for (int i = 0; i < spaceCount; i++) tabs.append(" "); - System.out.println(" " + out.append(" " + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + tabs + pd.getDescription()); + try { + Object def = pd.getField().get(pd.getObject()); + if (def != null) out.append(" (default: " + def + ")"); + } catch (IllegalArgumentException e) { + // ignore + } catch (IllegalAccessException e) { + // ignore + } + out.append("\n"); } + + System.out.println(out); } /** -- cgit v1.2.3 From 4ddd0bb457c9fc2ffbc5693142b2f451dbc4d15d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 07:40:30 -0700 Subject: Added addConverterFactory --- .../beust/jcommander/IStringConverterFactory.java | 12 +++++ src/main/java/com/beust/jcommander/JCommander.java | 41 ++++++++++++++--- .../com/beust/jcommander/ParameterDescription.java | 52 ++++++++++++---------- .../internal/DefaultConverterFactory.java | 33 ++++++++++++++ 4 files changed, 109 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IStringConverterFactory.java create mode 100644 src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IStringConverterFactory.java b/src/main/java/com/beust/jcommander/IStringConverterFactory.java new file mode 100644 index 0000000..8a514d7 --- /dev/null +++ b/src/main/java/com/beust/jcommander/IStringConverterFactory.java @@ -0,0 +1,12 @@ +package com.beust.jcommander; + +/** + * A factory for IStringConverter. This interface lets you specify your + * converters in one place instead of having them repeated all over + * your argument classes. + * + * @author cbeust + */ +public interface IStringConverterFactory { + Class> getConverter(Class forType); +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e36e120..d7b2e9d 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,5 +1,6 @@ package com.beust.jcommander; +import com.beust.jcommander.internal.DefaultConverterFactory; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; @@ -10,6 +11,7 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -74,8 +76,18 @@ public class JCommander { private ResourceBundle m_bundle; + /** + * A default provider returns default values for the parameters. + */ private IDefaultProvider m_defaultProvider; + /** + * The factories used to look up string converters. + */ + private List m_converterFactories = new ArrayList() {{ + add(new DefaultConverterFactory()); + }}; + public JCommander(Object object) { init(object, null); } @@ -108,17 +120,26 @@ public class JCommander { m_objects.add(object); } - createDescriptions(); } /** * Parse the command line parameters. */ public void parse(String... args) { + createDescriptions(); + initializeDefaultValues(); parseValues(expandArgs(args)); validateOptions(); } + private void initializeDefaultValues() { + if (m_defaultProvider != null) { + for (ParameterDescription pd : m_descriptions.values()) { + initializeDefaultValue(pd); + } + } + } + /** * Make sure that all the required parameters have received a value. */ @@ -282,7 +303,7 @@ public class JCommander { throw new ParameterException("Found the option " + name + " multiple times"); } p("Adding description for " + name); - ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle); + ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle, this); m_fields.put(f, pd); m_descriptions.put(name, pd); @@ -498,11 +519,19 @@ public class JCommander { */ public void setDefaultProvider(IDefaultProvider defaultProvider) { m_defaultProvider = defaultProvider; - if (m_defaultProvider != null) { - for (ParameterDescription pd : m_descriptions.values()) { - initializeDefaultValue(pd); - } + } + + public void addConverterFactory(IStringConverterFactory converterFactory) { + m_converterFactories.add(converterFactory); + } + + public Class> findConverter(Class cls) { + for (IStringConverterFactory f : m_converterFactories) { + Class> result = f.getConverter(cls); + if (result != null) return result; } + + return null; } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index a15f643..186c330 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -20,20 +20,6 @@ import java.util.ResourceBundle; import java.util.Set; public class ParameterDescription { - /** - * A map of converters per class. - */ - private static Map, Class>> m_classConverters - = new HashMap() {{ - put(String.class, StringConverter.class); - put(Integer.class, IntegerConverter.class); - put(int.class, IntegerConverter.class); - put(Long.class, LongConverter.class); - put(long.class, LongConverter.class); - put(Boolean.class, BooleanConverter.class); - put(boolean.class, BooleanConverter.class); - }}; - private Object m_object; private Parameter m_parameterAnnotation; private Field m_field; @@ -41,10 +27,11 @@ public class ParameterDescription { private boolean m_assigned = false; private ResourceBundle m_bundle; private String m_description; + private JCommander m_jCommander; public ParameterDescription(Object object, Parameter annotation, Field field, - ResourceBundle bundle) { - init(object, annotation, field, bundle); + ResourceBundle bundle, JCommander jc) { + init(object, annotation, field, bundle, jc); } /** @@ -72,7 +59,8 @@ public class ParameterDescription { return s == null || "".equals(s); } - private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle) { + private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle, + JCommander jCommander) { m_object = object; m_parameterAnnotation = annotation; m_field = field; @@ -80,6 +68,7 @@ public class ParameterDescription { if (m_bundle == null) { m_bundle = findResourceBundle(object); } + m_jCommander = jCommander; m_description = annotation.description(); if (! "".equals(annotation.descriptionKey())) { @@ -141,28 +130,45 @@ public class ParameterDescription { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + " once."); } - Class> converterClass = m_parameterAnnotation.converter(); + + Class type = m_field.getType(); + Class> converterClass = null; + + // + // Try to find a converter on the annotation + // + converterClass = m_parameterAnnotation.converter(); if (converterClass == NoConverter.class) { - converterClass = m_classConverters.get(m_field.getType()); + converterClass = m_jCommander.findConverter(type); } if (converterClass == null && m_parameterAnnotation.arity() >= 2) { converterClass = StringConverter.class; isCollection = true; } - if (converterClass == null && Collection.class.isAssignableFrom(m_field.getType())) { + if (converterClass == null && Collection.class.isAssignableFrom(type)) { converterClass = StringConverter.class; isCollection = true; } + + // +// // +// // Try to find a converter in the factory +// // +// IStringConverter converter = null; +// if (converterClass == null && m_converterFactories != null) { +// // Mmmh, javac requires a cast here +// converter = (IStringConverter) m_converterFactories.getConverter(type); +// } + if (converterClass == null) { throw new ParameterException("Don't know how to convert " + value - + " to type " + m_field.getType() + " (field: " + m_field.getName() + ")"); + + " to type " + type + " (field: " + m_field.getName() + ")"); } if (! isDefault) m_assigned = true; - IStringConverter converter; try { - converter = instantiateConverter(converterClass); + IStringConverter converter = instantiateConverter(converterClass); Object convertedValue = converter.convert(value); if (isCollection) { @SuppressWarnings("unchecked") diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java new file mode 100644 index 0000000..5d9da70 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -0,0 +1,33 @@ +package com.beust.jcommander.internal; + +import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.IStringConverterFactory; +import com.beust.jcommander.converters.BooleanConverter; +import com.beust.jcommander.converters.IntegerConverter; +import com.beust.jcommander.converters.LongConverter; +import com.beust.jcommander.converters.StringConverter; + +import java.util.Map; + +public class DefaultConverterFactory implements IStringConverterFactory { + /** + * A map of converters per class. + */ + private static Map>> m_classConverters; + + static { + m_classConverters = Maps.newHashMap(); + m_classConverters.put(String.class, StringConverter.class); + m_classConverters.put(Integer.class, IntegerConverter.class); + m_classConverters.put(int.class, IntegerConverter.class); + m_classConverters.put(Long.class, LongConverter.class); + m_classConverters.put(long.class, LongConverter.class); + m_classConverters.put(Boolean.class, BooleanConverter.class); + m_classConverters.put(boolean.class, BooleanConverter.class); + } + + public Class> getConverter(Class forType) { + return m_classConverters.get(forType); + } + +} -- cgit v1.2.3 From 67b245733f986c6b514f9121702d0c4289e3ae2d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 09:23:50 -0700 Subject: Converter factory test with HostPort --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++--- .../java/com/beust/jcommander/internal/DefaultConverterFactory.java | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d7b2e9d..f2f1fcc 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -84,7 +84,7 @@ public class JCommander { /** * The factories used to look up string converters. */ - private List m_converterFactories = new ArrayList() {{ + private static List CONVERTER_FACTORIES = new ArrayList() {{ add(new DefaultConverterFactory()); }}; @@ -522,11 +522,11 @@ public class JCommander { } public void addConverterFactory(IStringConverterFactory converterFactory) { - m_converterFactories.add(converterFactory); + CONVERTER_FACTORIES.add(converterFactory); } public Class> findConverter(Class cls) { - for (IStringConverterFactory f : m_converterFactories) { + for (IStringConverterFactory f : CONVERTER_FACTORIES) { Class> result = f.getConverter(cls); if (result != null) return result; } diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index 5d9da70..6781aa6 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -3,10 +3,12 @@ package com.beust.jcommander.internal; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.IStringConverterFactory; import com.beust.jcommander.converters.BooleanConverter; +import com.beust.jcommander.converters.FileConverter; import com.beust.jcommander.converters.IntegerConverter; import com.beust.jcommander.converters.LongConverter; import com.beust.jcommander.converters.StringConverter; +import java.io.File; import java.util.Map; public class DefaultConverterFactory implements IStringConverterFactory { @@ -24,6 +26,7 @@ public class DefaultConverterFactory implements IStringConverterFactory { m_classConverters.put(long.class, LongConverter.class); m_classConverters.put(Boolean.class, BooleanConverter.class); m_classConverters.put(boolean.class, BooleanConverter.class); + m_classConverters.put(File.class, FileConverter.class); } public Class> getConverter(Class forType) { -- cgit v1.2.3 From d556f4a527306a9769776d1cbb2fccac98618bc9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 09:49:20 -0700 Subject: Dash dash tests --- src/main/java/com/beust/jcommander/JCommander.java | 35 +++++++++++++--------- src/main/java/com/beust/jcommander/Parameters.java | 7 +++++ 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f2f1fcc..32844b9 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -186,20 +186,18 @@ public class JCommander { for (int i = 0; i < vResult1.size(); i++) { String arg = vResult1.get(i); // TODO: make sure it's really an option and not that it starts with "-" - if (isOption(arg)) { - if ("--".equals(arg)) { - vResult2.add(arg); - vResult2.add(vResult1.get(++i)); - } else { - String sep = getSeparatorFor(arg); - if (! " ".equals(sep)) { - String[] sp = arg.split("[" + sep + "]"); - for (String ssp : sp) { - vResult2.add(ssp); - } - } else { - vResult2.add(arg); + if ("--".equals(arg)) { + vResult2.add(arg); + vResult2.add(vResult1.get(++i)); + } else if (isOption(arg)) { + String sep = getSeparatorFor(arg); + if (! " ".equals(sep)) { + String[] sp = arg.split("[" + sep + "]"); + for (String ssp : sp) { + vResult2.add(ssp); } + } else { + vResult2.add(arg); } } else { vResult2.add(arg); @@ -210,7 +208,10 @@ public class JCommander { } private boolean isOption(String arg) { - return arg.startsWith("-"); + if ("--".equals(arg)) return false; + + String prefixes = getOptionPrefixes(); + return prefixes.indexOf(arg.charAt(0)) >= 0; } private ParameterDescription getDescriptionFor(String arg) { @@ -231,6 +232,12 @@ public class JCommander { else return " "; } + private String getOptionPrefixes() { + Parameters p = m_objects.get(0).getClass().getAnnotation(Parameters.class); + if (p != null) return p.optionPrefixes(); + else return Parameters.DEFAULT_OPTION_PREFIXES; + } + /** * Reads the file specified by filename and returns the file content as a string. * End of lines are replaced by a space. diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index 1feb224..07751a4 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -14,6 +14,8 @@ import java.lang.annotation.Target; @Target({ TYPE }) public @interface Parameters { + public static final String DEFAULT_OPTION_PREFIXES = "-"; + /** * The name of the resource bundle to use for this class. */ @@ -23,4 +25,9 @@ public @interface Parameters { * The character(s) that separate options. */ String separators() default " "; + + /** + * What characters an option starts with. + */ + String optionPrefixes() default DEFAULT_OPTION_PREFIXES; } -- cgit v1.2.3 From f14a46abd32b378ec56a672a2da0b926c5d7276d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 10:13:55 -0700 Subject: Flexible prefixes --- src/main/java/com/beust/jcommander/JCommander.java | 82 ++++++++++++++++------ 1 file changed, 61 insertions(+), 21 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 32844b9..d003512 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -126,12 +126,25 @@ public class JCommander { * Parse the command line parameters. */ public void parse(String... args) { + StringBuilder sb = new StringBuilder("Parsing \""); + sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray()))); + p(sb.toString()); + createDescriptions(); initializeDefaultValues(); parseValues(expandArgs(args)); validateOptions(); } + private StringBuilder join(Object[] args) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < args.length; i++) { + if (i > 0) result.append(" "); + result.append(args[i]); + } + return result; + } + private void initializeDefaultValues() { if (m_defaultProvider != null) { for (ParameterDescription pd : m_descriptions.values()) { @@ -185,12 +198,13 @@ public class JCommander { List vResult2 = Lists.newArrayList(); for (int i = 0; i < vResult1.size(); i++) { String arg = vResult1.get(i); + String[] v1 = vResult1.toArray(new String[0]); // TODO: make sure it's really an option and not that it starts with "-" if ("--".equals(arg)) { vResult2.add(arg); vResult2.add(vResult1.get(++i)); - } else if (isOption(arg)) { - String sep = getSeparatorFor(arg); + } else if (isOption(v1, arg)) { + String sep = getSeparatorFor(v1, arg); if (! " ".equals(sep)) { String[] sp = arg.split("[" + sep + "]"); for (String ssp : sp) { @@ -207,35 +221,61 @@ public class JCommander { return vResult2.toArray(new String[vResult2.size()]); } - private boolean isOption(String arg) { + private boolean isOption(String[] args, String arg) { if ("--".equals(arg)) return false; - String prefixes = getOptionPrefixes(); + String prefixes = getOptionPrefixes(args, arg); return prefixes.indexOf(arg.charAt(0)) >= 0; } - private ParameterDescription getDescriptionFor(String arg) { - for (ParameterDescription p : m_descriptions.values()) { - for (String n : p.getParameter().names()) { - if (arg.startsWith(n)) { - return p; - } - } + private ParameterDescription getPrefixDescriptionFor(String arg) { + for (Map.Entry es : m_descriptions.entrySet()) { + if (arg.startsWith(es.getKey())) return es.getValue(); + } + + return null; + } + + /** + * If arg is an option, we can look it up directly, but if it's a value, + * we need to find the description for the option that precedes it. + */ + private ParameterDescription getDescriptionFor(String[] args, String arg) { + ParameterDescription result = getPrefixDescriptionFor(arg); + if (result != null) return result; + + for (String a : args) { + ParameterDescription pd = getPrefixDescriptionFor(arg); + if (pd != null) result = pd; + if (a.equals(arg)) return result; } + throw new ParameterException("Unknown parameter: " + arg); } - private String getSeparatorFor(String arg) { - ParameterDescription pd = getDescriptionFor(arg); - Parameters p = pd.getObject().getClass().getAnnotation(Parameters.class); - if (p != null) return p.separators(); - else return " "; + private String getSeparatorFor(String[] args, String arg) { + ParameterDescription pd = getDescriptionFor(args, arg); + + // Could be null if only main parameters were passed + if (pd != null) { + Parameters p = pd.getObject().getClass().getAnnotation(Parameters.class); + if (p != null) return p.separators(); + } + + return " "; } - private String getOptionPrefixes() { - Parameters p = m_objects.get(0).getClass().getAnnotation(Parameters.class); - if (p != null) return p.optionPrefixes(); - else return Parameters.DEFAULT_OPTION_PREFIXES; + private String getOptionPrefixes(String[] args, String arg) { + ParameterDescription pd = getDescriptionFor(args, arg); + + // Could be null if only main parameters were passed + if (pd != null) { + Parameters p = pd.getObject().getClass() + .getAnnotation(Parameters.class); + if (p != null) return p.optionPrefixes(); + } + + return Parameters.DEFAULT_OPTION_PREFIXES; } /** @@ -340,7 +380,7 @@ public class JCommander { p("Parsing arg:" + a); // ParameterDescription previousDescription = null; - if (isOption(a)) { + if (isOption(args, a)) { ParameterDescription pd = m_descriptions.get(a); // ParameterDescription pd = null; // -- cgit v1.2.3 From 858c0e61453c4b3a8663d9094f38b6aba493d753 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 10:20:46 -0700 Subject: Better tests, updated CHANGELOG --- src/main/java/com/beust/jcommander/JCommander.java | 36 ++-------------------- 1 file changed, 2 insertions(+), 34 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d003512..d5c21ab 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -11,7 +11,6 @@ import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -199,11 +198,7 @@ public class JCommander { for (int i = 0; i < vResult1.size(); i++) { String arg = vResult1.get(i); String[] v1 = vResult1.toArray(new String[0]); - // TODO: make sure it's really an option and not that it starts with "-" - if ("--".equals(arg)) { - vResult2.add(arg); - vResult2.add(vResult1.get(++i)); - } else if (isOption(v1, arg)) { + if (isOption(v1, arg)) { String sep = getSeparatorFor(v1, arg); if (! " ".equals(sep)) { String[] sp = arg.split("[" + sep + "]"); @@ -222,8 +217,6 @@ public class JCommander { } private boolean isOption(String[] args, String arg) { - if ("--".equals(arg)) return false; - String prefixes = getOptionPrefixes(args, arg); return prefixes.indexOf(arg.charAt(0)) >= 0; } @@ -378,34 +371,9 @@ public class JCommander { for (int i = 0; i < args.length; i++) { String a = trim(args[i]); p("Parsing arg:" + a); -// ParameterDescription previousDescription = null; if (isOption(args, a)) { - ParameterDescription pd = m_descriptions.get(a); -// ParameterDescription pd = null; -// -// if ("--".equals(a)) { -// pd = previousDescription; -// i++; -// } else { -// } -// previousDescription = pd; - - // If we don't find any description, see if the previous parameter is an int - // or a long, and if it is, check to see if the current arg can be parsed - // into a negative integer -// if (pd == null && pd.isNumber()) { -// try { -// Long l = Long.parseLong(a); -// pd = previousDescription; -// i--; -// } -// catch(NumberFormatException ex) { -// // Do nothing, we'll fall through and throw a parameter exception -// } -// } -// -// previousDescription = pd; + ParameterDescription pd = m_descriptions.get(a); if (pd != null) { if (pd.getParameter().password()) { -- cgit v1.2.3 From 0c6350b606a1f72156f3564402c75dc11454ecf1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 12:53:31 -0700 Subject: Fixed a few generics warnings --- .../java/com/beust/jcommander/IStringConverterFactory.java | 2 +- src/main/java/com/beust/jcommander/JCommander.java | 12 +++++++----- src/main/java/com/beust/jcommander/ParameterDescription.java | 5 ----- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IStringConverterFactory.java b/src/main/java/com/beust/jcommander/IStringConverterFactory.java index 8a514d7..5a3b3b2 100644 --- a/src/main/java/com/beust/jcommander/IStringConverterFactory.java +++ b/src/main/java/com/beust/jcommander/IStringConverterFactory.java @@ -8,5 +8,5 @@ package com.beust.jcommander; * @author cbeust */ public interface IStringConverterFactory { - Class> getConverter(Class forType); + Class> getConverter(Class forType); } diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d5c21ab..1f36d1a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -83,9 +83,11 @@ public class JCommander { /** * The factories used to look up string converters. */ - private static List CONVERTER_FACTORIES = new ArrayList() {{ - add(new DefaultConverterFactory()); - }}; + private static List CONVERTER_FACTORIES = Lists.newArrayList(); + + static { + CONVERTER_FACTORIES.add(new DefaultConverterFactory()); + }; public JCommander(Object object) { init(object, null); @@ -540,9 +542,9 @@ public class JCommander { CONVERTER_FACTORIES.add(converterFactory); } - public Class> findConverter(Class cls) { + public Class> findConverter(Class cls) { for (IStringConverterFactory f : CONVERTER_FACTORIES) { - Class> result = f.getConverter(cls); + Class> result = f.getConverter(cls); if (result != null) return result; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 186c330..7ff6e02 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,9 +1,6 @@ package com.beust.jcommander; -import com.beust.jcommander.converters.BooleanConverter; -import com.beust.jcommander.converters.IntegerConverter; -import com.beust.jcommander.converters.LongConverter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; @@ -12,10 +9,8 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.ResourceBundle; import java.util.Set; -- cgit v1.2.3 From 0ec1bf37ff92ef52d0c37dfbd50a3a7284d5b460 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 20:24:28 -0700 Subject: Replace log() with p() --- src/main/java/com/beust/jcommander/ParameterDescription.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 7ff6e02..963e094 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -118,7 +118,7 @@ public class ParameterDescription { * @param markAdded if true, mark this parameter as assigned */ public void addValue(String value, boolean isDefault) { - log("Adding " + (isDefault ? "default " : "") + "value:" + value + p("Adding " + (isDefault ? "default " : "") + "value:" + value + " to parameter:" + m_field.getName()); boolean isCollection = false; if (m_assigned && ! isMultiOption()) { @@ -217,7 +217,7 @@ public class ParameterDescription { return result; } - private void log(String string) { + private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[ParameterDescription] " + string); } -- cgit v1.2.3 From 0235dc8adeed6c78d7f65a5766cd1886ef6e7b18 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 28 Jul 2010 22:12:26 -0700 Subject: Documented the new features --- src/main/java/com/beust/jcommander/JCommander.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1f36d1a..11b14b5 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -464,6 +464,8 @@ public class JCommander { * Display a the help on System.out. */ public void usage() { + if (m_descriptions == null) createDescriptions(); + StringBuilder sb = new StringBuilder("Usage:
[options]"); if (m_mainParameterAnnotation != null) { sb.append(" " + m_mainParameterAnnotation.description()); -- cgit v1.2.3 From 1eb22b901f731760a479740312337471363febff Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 29 Jul 2010 12:57:34 -0700 Subject: Moved findConverter to JCommander --- src/main/java/com/beust/jcommander/JCommander.java | 103 ++++++++++++++++++++- .../com/beust/jcommander/ParameterDescription.java | 97 +++++++------------ 2 files changed, 132 insertions(+), 68 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 11b14b5..aa6a4f6 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,5 +1,7 @@ package com.beust.jcommander; +import com.beust.jcommander.converters.NoConverter; +import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.DefaultConverterFactory; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; @@ -9,8 +11,12 @@ import java.io.Console; import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -98,6 +104,7 @@ public class JCommander { parse(args); } + public JCommander(Object object, String... args) { init(object, null); parse(args); @@ -425,7 +432,17 @@ public class JCommander { } } else { - if (! isStringEmpty(args[i])) getMainParameter(args[i]).add(args[i]); + if (! isStringEmpty(args[i])) { + List mp = getMainParameter(args[i]); + Object value = args[i]; + + if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); + System.out.println("Generic type:" + p.getActualTypeArguments()[0]); + } + + mp.add(value); + } } } } @@ -440,7 +457,7 @@ public class JCommander { * @param arg the arg that we're about to add (only passed here to ouput a meaningful * error message). */ - private List getMainParameter(String arg) { + private List getMainParameter(String arg) { if (m_mainParameterField == null) { throw new ParameterException( "Was passed main parameter '" + arg + "' but no main parameter was defined"); @@ -448,7 +465,7 @@ public class JCommander { try { @SuppressWarnings("unchecked") - List result = (List) m_mainParameterField.get(m_mainParameterObject); + List result = (List) m_mainParameterField.get(m_mainParameterObject); if (result == null) { result = Lists.newArrayList(); m_mainParameterField.set(m_mainParameterObject, result); @@ -552,5 +569,85 @@ public class JCommander { return null; } + + public Object convertValue(ParameterDescription pd, String value) { + Parameter annotation = pd.getParameter(); + Class type = pd.getField().getType(); + Class> converterClass = annotation.converter(); + + // + // Try to find a converter on the annotation + // + boolean isCollection = false; + + if (converterClass == null || converterClass == NoConverter.class) { + converterClass = findConverter(type); + } + if (converterClass == null) { + converterClass = StringConverter.class; + isCollection = true; + } + if (converterClass == null && Collection.class.isAssignableFrom(type)) { + converterClass = StringConverter.class; + isCollection = true; + } + + // +// // +// // Try to find a converter in the factory +// // +// IStringConverter converter = null; +// if (converterClass == null && m_converterFactories != null) { +// // Mmmh, javac requires a cast here +// converter = (IStringConverter) m_converterFactories.getConverter(type); +// } + + if (converterClass == null) { + throw new ParameterException("Don't know how to convert " + value + + " to type " + type + " (field: " + pd.getField().getName() + ")"); + } + + IStringConverter converter; + Object result = null; + try { + String optionName = annotation.names()[0]; + converter = instantiateConverter(optionName, converterClass); + result = converter.convert(value); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + return result; + } + + private IStringConverter instantiateConverter(String optionName, + Class> converterClass) + throws IllegalArgumentException, InstantiationException, IllegalAccessException, + InvocationTargetException { + Constructor> ctor = null; + Constructor> stringCtor = null; + Constructor>[] ctors + = (Constructor>[]) converterClass.getDeclaredConstructors(); + for (Constructor> c : ctors) { + Class[] types = c.getParameterTypes(); + if (types.length == 1 && types[0].equals(String.class)) { + stringCtor = c; + } else if (types.length == 0) { + ctor = c; + } + } + + IStringConverter result = stringCtor != null + ? stringCtor.newInstance(optionName) + : ctor.newInstance(); + + return result; + } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 963e094..ffe9c95 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -120,51 +120,41 @@ public class ParameterDescription { public void addValue(String value, boolean isDefault) { p("Adding " + (isDefault ? "default " : "") + "value:" + value + " to parameter:" + m_field.getName()); - boolean isCollection = false; if (m_assigned && ! isMultiOption()) { throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + " once."); } Class type = m_field.getType(); - Class> converterClass = null; - - // - // Try to find a converter on the annotation - // - converterClass = m_parameterAnnotation.converter(); - if (converterClass == NoConverter.class) { - converterClass = m_jCommander.findConverter(type); - } - if (converterClass == null && m_parameterAnnotation.arity() >= 2) { - converterClass = StringConverter.class; - isCollection = true; - } - if (converterClass == null && Collection.class.isAssignableFrom(type)) { - converterClass = StringConverter.class; - isCollection = true; - } - - // +// Class> converterClass = null; +// // // -// // Try to find a converter in the factory +// // Try to find a converter on the annotation // // -// IStringConverter converter = null; -// if (converterClass == null && m_converterFactories != null) { -// // Mmmh, javac requires a cast here -// converter = (IStringConverter) m_converterFactories.getConverter(type); +// converterClass = m_parameterAnnotation.converter(); +// if (converterClass == NoConverter.class) { +// converterClass = m_jCommander.findConverter(type); +// } +// if (converterClass == null && m_parameterAnnotation.arity() >= 2) { +// converterClass = StringConverter.class; +// isCollection = true; +// } +// if (converterClass == null && Collection.class.isAssignableFrom(type)) { +// converterClass = StringConverter.class; +// isCollection = true; +// } +// +// if (converterClass == null) { +// throw new ParameterException("Don't know how to convert " + value +// + " to type " + type + " (field: " + m_field.getName() + ")"); // } - - if (converterClass == null) { - throw new ParameterException("Don't know how to convert " + value - + " to type " + type + " (field: " + m_field.getName() + ")"); - } if (! isDefault) m_assigned = true; + Object convertedValue = m_jCommander.convertValue(this, value); + boolean isCollection = Collection.class.isAssignableFrom(type); + boolean isMainParameter = m_parameterAnnotation.names().length == 0; try { - IStringConverter converter = instantiateConverter(converterClass); - Object convertedValue = converter.convert(value); if (isCollection) { @SuppressWarnings("unchecked") List l = (List) m_field.get(m_object); @@ -172,18 +162,19 @@ public class ParameterDescription { l = Lists.newArrayList(); m_field.set(m_object, l); } - l.add(convertedValue); + if (convertedValue instanceof Collection) { + l.addAll((Collection) convertedValue); + } else { // if (isMainParameter || m_parameterAnnotation.arity() > 1) { + l.add(convertedValue); +// } else { +// l. + } } else { m_field.set(m_object, convertedValue); } - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); + } + catch(IllegalAccessException ex) { + ex.printStackTrace(); } } @@ -193,30 +184,6 @@ public class ParameterDescription { || type.equals(Long.class) || type.equals(long.class); } - private IStringConverter instantiateConverter( - Class> converterClass) - throws IllegalArgumentException, InstantiationException, IllegalAccessException, - InvocationTargetException { - Constructor> ctor = null; - Constructor> stringCtor = null; - Constructor>[] ctors - = (Constructor>[]) converterClass.getDeclaredConstructors(); - for (Constructor> c : ctors) { - Class[] types = c.getParameterTypes(); - if (types.length == 1 && types[0].equals(String.class)) { - stringCtor = c; - } else if (types.length == 0) { - ctor = c; - } - } - - IStringConverter result = stringCtor != null - ? stringCtor.newInstance(m_parameterAnnotation.names()[0]) - : ctor.newInstance(); - - return result; - } - private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[ParameterDescription] " + string); -- cgit v1.2.3 From 484d81b494104aa2b684dab7825466c7b98b744b Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 29 Jul 2010 13:59:22 -0700 Subject: Main parameters now use converters --- src/main/java/com/beust/jcommander/JCommander.java | 32 ++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index aa6a4f6..7dd05fe 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -15,6 +15,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -434,14 +435,18 @@ public class JCommander { else { if (! isStringEmpty(args[i])) { List mp = getMainParameter(args[i]); - Object value = args[i]; + String value = args[i]; + Object convertedValue = value; if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); - System.out.println("Generic type:" + p.getActualTypeArguments()[0]); + Type cls = p.getActualTypeArguments()[0]; + if (cls instanceof Class) { + convertedValue = convertValue(m_mainParameterField, (Class) cls, value); + } } - mp.add(value); + mp.add(convertedValue); } } } @@ -571,25 +576,29 @@ public class JCommander { } public Object convertValue(ParameterDescription pd, String value) { - Parameter annotation = pd.getParameter(); - Class type = pd.getField().getType(); + return convertValue(pd.getField(), pd.getField().getType(), value); + } + + /** + * @param type The class of the field + * @param annotation The annotation + * @param value The value to convert + */ + public Object convertValue(Field field, Class type, String value) { + Parameter annotation = field.getAnnotation(Parameter.class); Class> converterClass = annotation.converter(); // // Try to find a converter on the annotation // - boolean isCollection = false; - if (converterClass == null || converterClass == NoConverter.class) { converterClass = findConverter(type); } if (converterClass == null) { converterClass = StringConverter.class; - isCollection = true; } if (converterClass == null && Collection.class.isAssignableFrom(type)) { converterClass = StringConverter.class; - isCollection = true; } // @@ -604,13 +613,14 @@ public class JCommander { if (converterClass == null) { throw new ParameterException("Don't know how to convert " + value - + " to type " + type + " (field: " + pd.getField().getName() + ")"); + + " to type " + type + " (field: " + field.getName() + ")"); } IStringConverter converter; Object result = null; try { - String optionName = annotation.names()[0]; + String[] names = annotation.names(); + String optionName = names.length > 0 ? names[0] : "[Main class]"; converter = instantiateConverter(optionName, converterClass); result = converter.convert(value); } catch (IllegalArgumentException e) { -- cgit v1.2.3 From 5187242fcad293107312ef97c0d6552dfa5e3574 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 31 Jul 2010 09:44:36 -0700 Subject: Implemented commands. --- src/main/java/com/beust/jcommander/JCommander.java | 95 ++++++++++++++++++---- 1 file changed, 80 insertions(+), 15 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7dd05fe..3110fe4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -87,6 +87,16 @@ public class JCommander { */ private IDefaultProvider m_defaultProvider; + /** + * List of commands and their instance. + */ + private Map m_commands = Maps.newHashMap(); + + /** + * The name of the command after the parsing has run. + */ + private String m_parsedCommand; + /** * The factories used to look up string converters. */ @@ -331,6 +341,12 @@ public class JCommander { m_descriptions = Maps.newHashMap(); for (Object object : m_objects) { + addDescription(object); + } + } + + private void addDescription(Object object) { + { Class cls = object.getClass(); for (Field f : cls.getDeclaredFields()) { p("Field:" + f.getName()); @@ -378,11 +394,20 @@ public class JCommander { * Main method that parses the values and initializes the fields accordingly. */ private void parseValues(String[] args) { - for (int i = 0; i < args.length; i++) { - String a = trim(args[i]); + // This boolean becomes true if we encounter a command, which indicates we need + // to stop parsing (the parsing of the command will be done in a sub JCommander + // object) + boolean commandParsed = false; + int i = 0; + while (i < args.length && ! commandParsed) { + String arg = args[i]; + String a = trim(arg); p("Parsing arg:" + a); if (isOption(args, a)) { + // + // Option + // ParameterDescription pd = m_descriptions.get(a); if (pd != null) { @@ -424,7 +449,7 @@ public class JCommander { } i += n + offset; } else { - throw new ParameterException(n + " parameters expected after " + args[i]); + throw new ParameterException(n + " parameters expected after " + arg); } } } @@ -433,25 +458,53 @@ public class JCommander { } } else { - if (! isStringEmpty(args[i])) { - List mp = getMainParameter(args[i]); - String value = args[i]; - Object convertedValue = value; - - if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { - ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); - Type cls = p.getActualTypeArguments()[0]; - if (cls instanceof Class) { - convertedValue = convertValue(m_mainParameterField, (Class) cls, value); + // + // Main parameter + // + if (! isStringEmpty(arg)) { + if (m_commands.isEmpty()) { + // + // Regular (non-command) parsing + // + List mp = getMainParameter(arg); + String value = arg; + Object convertedValue = value; + + if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); + Type cls = p.getActualTypeArguments()[0]; + if (cls instanceof Class) { + convertedValue = convertValue(m_mainParameterField, (Class) cls, value); + } } + + mp.add(convertedValue); + } + else { + // + // Command parsing + // + Object o = m_commands.get(arg); + if (o == null) throw new ParameterException("Expected a command, got " + arg); + m_parsedCommand = arg; + JCommander jc = new JCommander(o); + jc.parse(subArray(args, i + 1)); + commandParsed = true; } - - mp.add(convertedValue); } } + i++; } } + private String[] subArray(String[] args, int index) { + int l = args.length - index; + String[] result = new String[l]; + System.arraycopy(args, index, result, 0, l); + + return result; + } + private static boolean isStringEmpty(String s) { return s == null || "".equals(s); } @@ -659,5 +712,17 @@ public class JCommander { return result; } + + /** + * Add a command object. + */ + public void addCommand(String string, Object object) { + m_commands.put(string, object); + } + + public String getParsedCommand() { + return m_parsedCommand; + } + } -- cgit v1.2.3 From d9912518ee6f7aeb843c4977f780fee30fad32d7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 31 Jul 2010 09:59:30 -0700 Subject: Moved command tests --- src/main/java/com/beust/jcommander/JCommander.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3110fe4..a0aeda3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -487,6 +487,11 @@ public class JCommander { Object o = m_commands.get(arg); if (o == null) throw new ParameterException("Expected a command, got " + arg); m_parsedCommand = arg; + + // Found a valid command, create a new JCommander object with its + // description object and ask it to parse the remainder of the arguments. + // Setting the boolean commandParsed to true will force the current + // loop to end. JCommander jc = new JCommander(o); jc.parse(subArray(args, i + 1)); commandParsed = true; -- cgit v1.2.3 From 3477b0f9a636d6e9be7dbc56d185cab426dc70bf Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 1 Aug 2010 15:15:57 -0700 Subject: Displaying correct usage for commands --- src/main/java/com/beust/jcommander/JCommander.java | 97 ++++++++++++++++++++-- .../com/beust/jcommander/ParameterDescription.java | 38 +++------ 2 files changed, 101 insertions(+), 34 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index a0aeda3..76ed929 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -97,6 +97,8 @@ public class JCommander { */ private String m_parsedCommand; + private String m_programName; + /** * The factories used to look up string converters. */ @@ -540,20 +542,68 @@ public class JCommander { } } + private String getMainParameterDescription() { + if (m_descriptions == null) createDescriptions(); + return m_mainParameterAnnotation != null ? m_mainParameterAnnotation.description() + : null; + } + + private int longestName(Collection objects) { + int result = 0; + for (Object o : objects) { + int l = o.toString().length(); + if (l > result) result = l; + } + + return result; + } + + public void usage(String commandName) { + Object o = m_commands.get(commandName); + Object object; + try { + // Create a new object since o might have received values + // and might therefore display default values that are incorrect. + object = o.getClass().newInstance(); + JCommander jc = new JCommander(object); + jc.setProgramName(commandName); + jc.usage(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * Set the program name (used only in the usage). + */ + public void setProgramName(String name) { + m_programName = name; + } + /** * Display a the help on System.out. */ public void usage() { if (m_descriptions == null) createDescriptions(); + boolean hasCommands = ! m_commands.isEmpty(); - StringBuilder sb = new StringBuilder("Usage:
[options]"); + // + // First line of the usage + // + String programName = m_programName != null ? m_programName : "
"; + StringBuilder sb = new StringBuilder("Usage: " + programName + " [options]"); + if (hasCommands) sb.append(" [command] [command options]"); if (m_mainParameterAnnotation != null) { sb.append(" " + m_mainParameterAnnotation.description()); } sb.append("\n Options:"); System.out.println(sb.toString()); - // Will contain the size of the longest option name + // + // Align the descriptions at the "longestName" column + // int longestName = 0; List sorted = Lists.newArrayList(); for (ParameterDescription pd : m_fields.values()) { @@ -567,6 +617,9 @@ public class JCommander { } } + // + // Sort the options + // Collections.sort(sorted, new Comparator() { @Override public int compare(ParameterDescription arg0, ParameterDescription arg1) { @@ -574,19 +627,21 @@ public class JCommander { } }); - // Display all the names and descriptions at the right tab position + // + // Display all the names and descriptions + // StringBuilder out = new StringBuilder(); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; - StringBuilder tabs = new StringBuilder(); - for (int i = 0; i < spaceCount; i++) tabs.append(" "); out.append(" " + (pd.getParameter().required() ? "* " : " ") - + pd.getNames() + tabs + pd.getDescription()); + + pd.getNames() + s(spaceCount) + pd.getDescription()); try { - Object def = pd.getField().get(pd.getObject()); - if (def != null) out.append(" (default: " + def + ")"); + if (! pd.wasAssigned()) { + Object def = pd.getField().get(pd.getObject()); + if (def != null) out.append(" (default: " + def + ")"); + } } catch (IllegalArgumentException e) { // ignore } catch (IllegalAccessException e) { @@ -595,6 +650,21 @@ public class JCommander { out.append("\n"); } + // + // If commands were specified, show them as well + // + if (hasCommands) { + out.append(" Commands:\n"); + int ln = longestName(m_commands.keySet()) + 3; + for (Map.Entry commands : m_commands.entrySet()) { + String name = commands.getKey(); + int spaceCount = ln - name.length(); + Object o = commands.getValue(); + JCommander jc = new JCommander(o); + out.append(" " + name + s(spaceCount) + jc.getMainParameterDescription() + "\n"); + } + } + System.out.println(out); } @@ -729,5 +799,16 @@ public class JCommander { return m_parsedCommand; } + /** + * @return n spaces + */ + private String s(int count) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < count; i++) { + result.append(" "); + } + + return result.toString(); + } } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index ffe9c95..fdac1d8 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,13 +1,9 @@ package com.beust.jcommander; -import com.beust.jcommander.converters.NoConverter; -import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.Lists; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.List; import java.util.Locale; @@ -111,6 +107,13 @@ public class ParameterDescription { addValue(value, false /* not default */); } + /** + * @return true if this parameter received a value during the parsing phase. + */ + public boolean wasAssigned() { + return m_assigned; + } + /** * Add the specified value to the field. First look up any field converter, then * any type converter, and if we can't find any, throw an exception. @@ -126,28 +129,6 @@ public class ParameterDescription { } Class type = m_field.getType(); -// Class> converterClass = null; -// -// // -// // Try to find a converter on the annotation -// // -// converterClass = m_parameterAnnotation.converter(); -// if (converterClass == NoConverter.class) { -// converterClass = m_jCommander.findConverter(type); -// } -// if (converterClass == null && m_parameterAnnotation.arity() >= 2) { -// converterClass = StringConverter.class; -// isCollection = true; -// } -// if (converterClass == null && Collection.class.isAssignableFrom(type)) { -// converterClass = StringConverter.class; -// isCollection = true; -// } -// -// if (converterClass == null) { -// throw new ParameterException("Don't know how to convert " + value -// + " to type " + type + " (field: " + m_field.getName() + ")"); -// } if (! isDefault) m_assigned = true; Object convertedValue = m_jCommander.convertValue(this, value); @@ -189,4 +170,9 @@ public class ParameterDescription { System.out.println("[ParameterDescription] " + string); } } + + @Override + public String toString() { + return "[ParameterDescription " + m_field.getName() + "]"; + } } -- cgit v1.2.3 From b7e9d9cfe060b02437f867716a8902cc466b0776 Mon Sep 17 00:00:00 2001 From: Guillaume Sauthier Date: Wed, 4 Aug 2010 13:25:24 +0200 Subject: Add inheritance support --- src/main/java/com/beust/jcommander/JCommander.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 76ed929..fd2ff61 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -348,10 +348,11 @@ public class JCommander { } private void addDescription(Object object) { - { - Class cls = object.getClass(); + Class cls = object.getClass(); + + while (!Object.class.equals(cls)) { for (Field f : cls.getDeclaredFields()) { - p("Field:" + f.getName()); + p("Field:" + cls.getSimpleName() + "." + f.getName()); f.setAccessible(true); Annotation annotation = f.getAnnotation(Parameter.class); if (annotation != null) { @@ -380,6 +381,8 @@ public class JCommander { } } } + // Traverse the super class until we find Object.class + cls = cls.getSuperclass(); } } -- cgit v1.2.3 From 58a4af720c30d8dba072a96e3713577c8d30aeae Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 5 Aug 2010 21:28:33 -0700 Subject: Added license headers with mvn -P license license:format --- .../java/com/beust/jcommander/IDefaultProvider.java | 18 ++++++++++++++++++ .../java/com/beust/jcommander/IStringConverter.java | 18 ++++++++++++++++++ .../com/beust/jcommander/IStringConverterFactory.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/JCommander.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/Parameter.java | 18 ++++++++++++++++++ .../com/beust/jcommander/ParameterDescription.java | 18 ++++++++++++++++++ .../java/com/beust/jcommander/ParameterException.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/Parameters.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/ResourceBundle.java | 18 ++++++++++++++++++ .../com/beust/jcommander/converters/BaseConverter.java | 18 ++++++++++++++++++ .../beust/jcommander/converters/BooleanConverter.java | 18 ++++++++++++++++++ .../jcommander/converters/CommaSeparatedConverter.java | 18 ++++++++++++++++++ .../com/beust/jcommander/converters/FileConverter.java | 18 ++++++++++++++++++ .../beust/jcommander/converters/IntegerConverter.java | 18 ++++++++++++++++++ .../com/beust/jcommander/converters/LongConverter.java | 18 ++++++++++++++++++ .../com/beust/jcommander/converters/NoConverter.java | 18 ++++++++++++++++++ .../beust/jcommander/converters/StringConverter.java | 18 ++++++++++++++++++ .../defaultprovider/PropertyFileDefaultProvider.java | 18 ++++++++++++++++++ .../jcommander/internal/DefaultConverterFactory.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/internal/Lists.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/internal/Maps.java | 18 ++++++++++++++++++ src/main/java/com/beust/jcommander/internal/Sets.java | 18 ++++++++++++++++++ 22 files changed, 396 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IDefaultProvider.java b/src/main/java/com/beust/jcommander/IDefaultProvider.java index 5ea0bc1..0353928 100644 --- a/src/main/java/com/beust/jcommander/IDefaultProvider.java +++ b/src/main/java/com/beust/jcommander/IDefaultProvider.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; /** diff --git a/src/main/java/com/beust/jcommander/IStringConverter.java b/src/main/java/com/beust/jcommander/IStringConverter.java index 53cd35f..fb51a79 100644 --- a/src/main/java/com/beust/jcommander/IStringConverter.java +++ b/src/main/java/com/beust/jcommander/IStringConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; /** diff --git a/src/main/java/com/beust/jcommander/IStringConverterFactory.java b/src/main/java/com/beust/jcommander/IStringConverterFactory.java index 5a3b3b2..0e53ca0 100644 --- a/src/main/java/com/beust/jcommander/IStringConverterFactory.java +++ b/src/main/java/com/beust/jcommander/IStringConverterFactory.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; /** diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 76ed929..247de7f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; import com.beust.jcommander.converters.NoConverter; diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 741dbf5..24fa469 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index fdac1d8..6adbc09 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java index 81353bf..8bf5a20 100644 --- a/src/main/java/com/beust/jcommander/ParameterException.java +++ b/src/main/java/com/beust/jcommander/ParameterException.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; public class ParameterException extends RuntimeException { diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index 07751a4..b716ebe 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; import static java.lang.annotation.ElementType.TYPE; diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java index 94df0ae..8309216 100644 --- a/src/main/java/com/beust/jcommander/ResourceBundle.java +++ b/src/main/java/com/beust/jcommander/ResourceBundle.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander; import static java.lang.annotation.ElementType.TYPE; diff --git a/src/main/java/com/beust/jcommander/converters/BaseConverter.java b/src/main/java/com/beust/jcommander/converters/BaseConverter.java index 94ceaf8..c560af3 100644 --- a/src/main/java/com/beust/jcommander/converters/BaseConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BaseConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java index 30fdf1a..9ca299f 100644 --- a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java index 44c3455..252aa6e 100644 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/converters/FileConverter.java b/src/main/java/com/beust/jcommander/converters/FileConverter.java index 36364fc..a54ec83 100644 --- a/src/main/java/com/beust/jcommander/converters/FileConverter.java +++ b/src/main/java/com/beust/jcommander/converters/FileConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index 4fdf77e..766bd11 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index b3cec97..5dd8b6a 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; diff --git a/src/main/java/com/beust/jcommander/converters/NoConverter.java b/src/main/java/com/beust/jcommander/converters/NoConverter.java index bae1898..eac2ef5 100644 --- a/src/main/java/com/beust/jcommander/converters/NoConverter.java +++ b/src/main/java/com/beust/jcommander/converters/NoConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/converters/StringConverter.java b/src/main/java/com/beust/jcommander/converters/StringConverter.java index 05fec0e..2971a9c 100644 --- a/src/main/java/com/beust/jcommander/converters/StringConverter.java +++ b/src/main/java/com/beust/jcommander/converters/StringConverter.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java index 50f33a4..47eeedb 100644 --- a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java +++ b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.defaultprovider; import com.beust.jcommander.IDefaultProvider; diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index 6781aa6..bbe0cd1 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.internal; import com.beust.jcommander.IStringConverter; diff --git a/src/main/java/com/beust/jcommander/internal/Lists.java b/src/main/java/com/beust/jcommander/internal/Lists.java index 8cacc33..8666fe4 100644 --- a/src/main/java/com/beust/jcommander/internal/Lists.java +++ b/src/main/java/com/beust/jcommander/internal/Lists.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.internal; import java.util.ArrayList; diff --git a/src/main/java/com/beust/jcommander/internal/Maps.java b/src/main/java/com/beust/jcommander/internal/Maps.java index 6a0dba6..9b476d0 100644 --- a/src/main/java/com/beust/jcommander/internal/Maps.java +++ b/src/main/java/com/beust/jcommander/internal/Maps.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.internal; import java.util.HashMap; diff --git a/src/main/java/com/beust/jcommander/internal/Sets.java b/src/main/java/com/beust/jcommander/internal/Sets.java index ced1045..221376a 100644 --- a/src/main/java/com/beust/jcommander/internal/Sets.java +++ b/src/main/java/com/beust/jcommander/internal/Sets.java @@ -1,3 +1,21 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.beust.jcommander.internal; import java.util.HashSet; -- cgit v1.2.3 From 2384cc9b2d354441c7faef9d6703baf307c65d45 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 5 Aug 2010 21:59:22 -0700 Subject: Added overloaded versions of usage() with StringBuilders --- src/main/java/com/beust/jcommander/JCommander.java | 43 +++++++++++++++------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 283f9aa..bfef376 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -579,7 +579,26 @@ public class JCommander { return result; } + /** + * Set the program name (used only in the usage). + */ + public void setProgramName(String name) { + m_programName = name; + } + + /** + * Display the usage for this command. + */ public void usage(String commandName) { + StringBuilder sb = new StringBuilder(); + usage(commandName, sb); + System.out.println(sb.toString()); + } + + /** + * Store the help for the command in the passed string builder. + */ + public void usage(String commandName, StringBuilder out) { Object o = m_commands.get(commandName); Object object; try { @@ -597,16 +616,18 @@ public class JCommander { } /** - * Set the program name (used only in the usage). + * Display a the help on System.out. */ - public void setProgramName(String name) { - m_programName = name; + public void usage() { + StringBuilder sb = new StringBuilder(); + usage(sb); + System.out.println(sb.toString()); } /** - * Display a the help on System.out. + * Store the help in the passed string builder. */ - public void usage() { + public void usage(StringBuilder out) { if (m_descriptions == null) createDescriptions(); boolean hasCommands = ! m_commands.isEmpty(); @@ -614,13 +635,12 @@ public class JCommander { // First line of the usage // String programName = m_programName != null ? m_programName : "
"; - StringBuilder sb = new StringBuilder("Usage: " + programName + " [options]"); - if (hasCommands) sb.append(" [command] [command options]"); + out.append("Usage: " + programName + " [options]"); + if (hasCommands) out.append(" [command] [command options]"); if (m_mainParameterAnnotation != null) { - sb.append(" " + m_mainParameterAnnotation.description()); + out.append(" " + m_mainParameterAnnotation.description()); } - sb.append("\n Options:"); - System.out.println(sb.toString()); + out.append("\n Options:"); // // Align the descriptions at the "longestName" column @@ -651,7 +671,6 @@ public class JCommander { // // Display all the names and descriptions // - StringBuilder out = new StringBuilder(); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; @@ -685,8 +704,6 @@ public class JCommander { out.append(" " + name + s(spaceCount) + jc.getMainParameterDescription() + "\n"); } } - - System.out.println(out); } /** -- cgit v1.2.3 From 72cacbaebb04753ddba0c8dc0f9328310e8cb222 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 15 Aug 2010 17:23:00 -0700 Subject: Added: now throwing an exception if required main parameters are not supplied --- src/main/java/com/beust/jcommander/JCommander.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bfef376..c4bf542 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -83,6 +83,8 @@ public class JCommander { */ private Parameter m_mainParameterAnnotation; + private ParameterDescription m_mainParameterDescription; + /** * A set of all the fields that are required. During the reflection phase, * this field receives all the fields that are annotated with required=true @@ -203,7 +205,14 @@ public class JCommander { } throw new ParameterException("The following options are required: " + missingFields); } - + + if (m_mainParameterDescription != null) { + if (m_mainParameterDescription.getParameter().required() && + !m_mainParameterDescription.wasAssigned()) { + throw new ParameterException("Main parameters are required (\"" + + m_mainParameterDescription.getDescription() + "\")"); + } + } } /** @@ -384,6 +393,7 @@ public class JCommander { m_mainParameterField = f; m_mainParameterObject = object; m_mainParameterAnnotation = p; + m_mainParameterDescription = new ParameterDescription(object, p, f, m_bundle, this); } else { for (String name : p.names()) { if (m_descriptions.containsKey(name)) { -- cgit v1.2.3 From 0bf62c0269798a001ef93dcf9bb9776a95f6052f Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 16 Aug 2010 19:49:42 -0700 Subject: Renaming --- src/main/java/com/beust/jcommander/JCommander.java | 5 +++-- src/main/java/com/beust/jcommander/ParameterDescription.java | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c4bf542..a2d640a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -208,7 +208,7 @@ public class JCommander { if (m_mainParameterDescription != null) { if (m_mainParameterDescription.getParameter().required() && - !m_mainParameterDescription.wasAssigned()) { + !m_mainParameterDescription.isAssigned()) { throw new ParameterException("Main parameters are required (\"" + m_mainParameterDescription.getDescription() + "\")"); } @@ -511,6 +511,7 @@ public class JCommander { } } + m_mainParameterDescription.setAssigned(true); mp.add(convertedValue); } else { @@ -688,7 +689,7 @@ public class JCommander { + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + s(spaceCount) + pd.getDescription()); try { - if (! pd.wasAssigned()) { + if (! pd.isAssigned()) { Object def = pd.getField().get(pd.getObject()); if (def != null) out.append(" (default: " + def + ")"); } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 6adbc09..015a897 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -128,10 +128,15 @@ public class ParameterDescription { /** * @return true if this parameter received a value during the parsing phase. */ - public boolean wasAssigned() { + public boolean isAssigned() { return m_assigned; } + + public void setAssigned(boolean b) { + m_assigned = true; + } + /** * Add the specified value to the field. First look up any field converter, then * any type converter, and if we can't find any, throw an exception. -- cgit v1.2.3 From b89d58db97bc7514cc20f6758f413088aea5672d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 16 Aug 2010 21:45:23 -0700 Subject: Applied jstrachan's patch for usage --- src/main/java/com/beust/jcommander/JCommander.java | 53 ++++++++-------------- .../com/beust/jcommander/ParameterDescription.java | 10 ++++ 2 files changed, 28 insertions(+), 35 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index a2d640a..67b8208 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -110,7 +110,7 @@ public class JCommander { /** * List of commands and their instance. */ - private Map m_commands = Maps.newHashMap(); + private Map m_commands = Maps.newHashMap(); /** * The name of the command after the parsing has run. @@ -518,15 +518,13 @@ public class JCommander { // // Command parsing // - Object o = m_commands.get(arg); - if (o == null) throw new ParameterException("Expected a command, got " + arg); + JCommander jc = m_commands.get(arg); + if (jc == null) throw new ParameterException("Expected a command, got " + arg); m_parsedCommand = arg; - // Found a valid command, create a new JCommander object with its - // description object and ask it to parse the remainder of the arguments. + // Found a valid command, ask it to parse the remainder of the arguments. // Setting the boolean commandParsed to true will force the current // loop to end. - JCommander jc = new JCommander(o); jc.parse(subArray(args, i + 1)); commandParsed = true; } @@ -610,20 +608,13 @@ public class JCommander { * Store the help for the command in the passed string builder. */ public void usage(String commandName, StringBuilder out) { - Object o = m_commands.get(commandName); - Object object; - try { - // Create a new object since o might have received values - // and might therefore display default values that are incorrect. - object = o.getClass().newInstance(); - JCommander jc = new JCommander(object); - jc.setProgramName(commandName); - jc.usage(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); + JCommander jc = m_commands.get(commandName); + String description = jc.getMainParameterDescription(); + if (description != null) { + out.append(description); + out.append("\n"); } + jc.usage(out); } /** @@ -688,17 +679,8 @@ public class JCommander { out.append(" " + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + s(spaceCount) + pd.getDescription()); - try { - if (! pd.isAssigned()) { - Object def = pd.getField().get(pd.getObject()); - if (def != null) out.append(" (default: " + def + ")"); - } - } catch (IllegalArgumentException e) { - // ignore - } catch (IllegalAccessException e) { - // ignore - } - out.append("\n"); + Object def = pd.getDefault(); + if (def != null) out.append(" (default: " + def + ")"); out.append("\n"); } // @@ -707,11 +689,10 @@ public class JCommander { if (hasCommands) { out.append(" Commands:\n"); int ln = longestName(m_commands.keySet()) + 3; - for (Map.Entry commands : m_commands.entrySet()) { + for (Map.Entry commands : m_commands.entrySet()) { String name = commands.getKey(); int spaceCount = ln - name.length(); - Object o = commands.getValue(); - JCommander jc = new JCommander(o); + JCommander jc = commands.getValue(); out.append(" " + name + s(spaceCount) + jc.getMainParameterDescription() + "\n"); } } @@ -840,8 +821,10 @@ public class JCommander { /** * Add a command object. */ - public void addCommand(String string, Object object) { - m_commands.put(string, object); + public void addCommand(String name, Object object) { + JCommander jc = new JCommander(object); + jc.setProgramName(name); + m_commands.put(name, jc); } public String getParsedCommand() { diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 015a897..f265cae 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -37,6 +37,7 @@ public class ParameterDescription { private ResourceBundle m_bundle; private String m_description; private JCommander m_jCommander; + private Object m_default; public ParameterDescription(Object object, Parameter annotation, Field field, ResourceBundle bundle, JCommander jc) { @@ -89,6 +90,15 @@ public class ParameterDescription { // "default description:'" + m_description + "'"); } } + + try { + m_default = m_field.get(m_object); + } catch (Exception e) { + } + } + + public Object getDefault() { + return m_default; } public String getDescription() { -- cgit v1.2.3 From 30e1bb6cbc100c085435a7abdae9d272603726b3 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 16 Aug 2010 22:32:40 -0700 Subject: Added Javadoc comments --- src/main/java/com/beust/jcommander/JCommander.java | 13 ++++++++++++- .../java/com/beust/jcommander/converters/BaseConverter.java | 5 +++++ .../com/beust/jcommander/converters/BooleanConverter.java | 5 +++++ .../jcommander/converters/CommaSeparatedConverter.java | 5 +++++ .../java/com/beust/jcommander/converters/FileConverter.java | 5 +++++ .../com/beust/jcommander/converters/IntegerConverter.java | 5 +++++ .../java/com/beust/jcommander/converters/LongConverter.java | 5 +++++ .../java/com/beust/jcommander/converters/NoConverter.java | 5 +++++ .../com/beust/jcommander/converters/StringConverter.java | 5 +++++ 9 files changed, 52 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 67b8208..a34a861 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -128,16 +128,27 @@ public class JCommander { CONVERTER_FACTORIES.add(new DefaultConverterFactory()); }; + /** + * @param object The arg object expected to contain {@link @Parameter} annotations. + */ public JCommander(Object object) { init(object, null); } + /** + * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param bundle The bundle to use for the descriptions. Can be null. + * @param args The arguments to parse (optional). + */ public JCommander(Object object, ResourceBundle bundle, String... args) { init(object, bundle); parse(args); } - + /** + * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param args The arguments to parse (optional). + */ public JCommander(Object object, String... args) { init(object, null); parse(args); diff --git a/src/main/java/com/beust/jcommander/converters/BaseConverter.java b/src/main/java/com/beust/jcommander/converters/BaseConverter.java index c560af3..4287163 100644 --- a/src/main/java/com/beust/jcommander/converters/BaseConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BaseConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; +/** + * Base class for converters that stores the name of the option. + * + * @author cbeust + */ abstract public class BaseConverter implements IStringConverter { private String m_optionName; diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java index 9ca299f..35188ca 100644 --- a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; +/** + * Converts a string to a boolean. + * + * @author cbeust + */ public class BooleanConverter extends BaseConverter { public BooleanConverter(String optionName) { diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java index 252aa6e..033138a 100644 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java @@ -23,6 +23,11 @@ import com.beust.jcommander.IStringConverter; import java.util.Arrays; import java.util.List; +/** + * Convert a string of comma separated words into a list of string. + * + * @author cbeust + */ public class CommaSeparatedConverter implements IStringConverter> { @Override diff --git a/src/main/java/com/beust/jcommander/converters/FileConverter.java b/src/main/java/com/beust/jcommander/converters/FileConverter.java index a54ec83..ea4d9ba 100644 --- a/src/main/java/com/beust/jcommander/converters/FileConverter.java +++ b/src/main/java/com/beust/jcommander/converters/FileConverter.java @@ -22,6 +22,11 @@ import com.beust.jcommander.IStringConverter; import java.io.File; +/** + * Convert a string into a file. + * + * @author cbeust + */ public class FileConverter implements IStringConverter { @Override diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index 766bd11..be38126 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; +/** + * Convert a string to an integer. + * + * @author cbeust + */ public class IntegerConverter extends BaseConverter { public IntegerConverter(String optionName) { diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index 5dd8b6a..bbfa0cf 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; +/** + * Convert a string to a long. + * + * @author cbeust + */ public class LongConverter extends BaseConverter { public LongConverter(String optionName) { diff --git a/src/main/java/com/beust/jcommander/converters/NoConverter.java b/src/main/java/com/beust/jcommander/converters/NoConverter.java index eac2ef5..c670258 100644 --- a/src/main/java/com/beust/jcommander/converters/NoConverter.java +++ b/src/main/java/com/beust/jcommander/converters/NoConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; +/** + * Default value for a converter when none is specified. + * + * @author cbeust + */ public class NoConverter implements IStringConverter { @Override diff --git a/src/main/java/com/beust/jcommander/converters/StringConverter.java b/src/main/java/com/beust/jcommander/converters/StringConverter.java index 2971a9c..1dce8b8 100644 --- a/src/main/java/com/beust/jcommander/converters/StringConverter.java +++ b/src/main/java/com/beust/jcommander/converters/StringConverter.java @@ -20,6 +20,11 @@ package com.beust.jcommander.converters; import com.beust.jcommander.IStringConverter; +/** + * Default converter for strings. + * + * @author cbeust + */ public class StringConverter implements IStringConverter { @Override -- cgit v1.2.3 From 29f59c27f3fd730f0b2ec02bd3a0db799dfa27a8 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 16 Aug 2010 22:41:49 -0700 Subject: Added newline in the usage --- src/main/java/com/beust/jcommander/JCommander.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index a34a861..9fc2dd3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -650,6 +650,7 @@ public class JCommander { String programName = m_programName != null ? m_programName : "
"; out.append("Usage: " + programName + " [options]"); if (hasCommands) out.append(" [command] [command options]"); + out.append("\n"); if (m_mainParameterAnnotation != null) { out.append(" " + m_mainParameterAnnotation.description()); } -- cgit v1.2.3 From dda1651c0b74aa9e8d225096f1d531871460e692 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 25 Aug 2010 18:54:58 -0700 Subject: Added: @Parameters(commandDescription = "command description") --- src/main/java/com/beust/jcommander/JCommander.java | 35 +++++++++++++++++----- src/main/java/com/beust/jcommander/Parameters.java | 7 +++++ 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9fc2dd3..d1f2ea1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -619,13 +619,25 @@ public class JCommander { * Store the help for the command in the passed string builder. */ public void usage(String commandName, StringBuilder out) { - JCommander jc = m_commands.get(commandName); - String description = jc.getMainParameterDescription(); + String description = getCommandDescription(commandName); + if (description != null) { out.append(description); out.append("\n"); } - jc.usage(out); + usage(out); + } + + /** + * @return the description of the command. + */ + public String getCommandDescription(String commandName) { + JCommander jc = m_commands.get(commandName); + Parameters p = jc.getObjects().get(0).getClass().getAnnotation(Parameters.class); + String result = jc.getMainParameterDescription(); + if (p != null) result = p.commandDescription(); + + return result; } /** @@ -652,9 +664,9 @@ public class JCommander { if (hasCommands) out.append(" [command] [command options]"); out.append("\n"); if (m_mainParameterAnnotation != null) { - out.append(" " + m_mainParameterAnnotation.description()); + out.append(" " + m_mainParameterAnnotation.description() + "\n"); } - out.append("\n Options:"); + out.append(" Options:"); // // Align the descriptions at the "longestName" column @@ -700,12 +712,13 @@ public class JCommander { // if (hasCommands) { out.append(" Commands:\n"); + // The magic value 3 is the number of spaces between the name of the option + // and its description int ln = longestName(m_commands.keySet()) + 3; for (Map.Entry commands : m_commands.entrySet()) { String name = commands.getKey(); int spaceCount = ln - name.length(); - JCommander jc = commands.getValue(); - out.append(" " + name + s(spaceCount) + jc.getMainParameterDescription() + "\n"); + out.append(" " + name + s(spaceCount) + getCommandDescription(name) + "\n"); } } } @@ -854,5 +867,13 @@ public class JCommander { return result.toString(); } + + /** + * @return the objects that JCommander will fill with the result of + * parsing the command line. + */ + public List getObjects() { + return m_objects; + } } diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index b716ebe..8f1cf82 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -48,4 +48,11 @@ public @interface Parameters { * What characters an option starts with. */ String optionPrefixes() default DEFAULT_OPTION_PREFIXES; + + /** + * If this class was added to {@link JCommander} as a command {@see JCommander#addCommand}, + * then this string will be displayed in the description when @{link JCommander#usage} is + * invoked. + */ + String commandDescription() default ""; } -- cgit v1.2.3 From 2b0f4c4b974d037ffe7961e90458a668ea9738be Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 31 Aug 2010 22:03:14 -0700 Subject: Fixed: Minor bug in the command display (Marc Ende) --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d1f2ea1..b60a1e3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -620,12 +620,12 @@ public class JCommander { */ public void usage(String commandName, StringBuilder out) { String description = getCommandDescription(commandName); - + JCommander jc = m_commands.get(commandName); if (description != null) { out.append(description); out.append("\n"); } - usage(out); + jc.usage(out); } /** -- cgit v1.2.3 From a5355541be1ffe1867657e71d134b77a7747a7ed Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 31 Aug 2010 22:04:04 -0700 Subject: Javadoc fix. --- src/main/java/com/beust/jcommander/Parameters.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index 8f1cf82..cffc030 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -50,9 +50,9 @@ public @interface Parameters { String optionPrefixes() default DEFAULT_OPTION_PREFIXES; /** - * If this class was added to {@link JCommander} as a command {@see JCommander#addCommand}, - * then this string will be displayed in the description when @{link JCommander#usage} is - * invoked. + * If the annotated class was added to {@link JCommander} as a command with + * {@link JCommander#addCommand}, then this string will be displayed in the + * description when @{link JCommander#usage} is invoked. */ String commandDescription() default ""; } -- cgit v1.2.3 From 4c020da73b8b25773bba8553263cf1954c718573 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 31 Aug 2010 22:23:52 -0700 Subject: Added: Command usages are now shown in the order they were added to the JCommander object. --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++++- src/main/java/com/beust/jcommander/internal/Maps.java | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b60a1e3..f0c7d5a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -110,7 +110,7 @@ public class JCommander { /** * List of commands and their instance. */ - private Map m_commands = Maps.newHashMap(); + private Map m_commands = Maps.newLinkedHashMap(); /** * The name of the command after the parsing has run. @@ -852,6 +852,10 @@ public class JCommander { m_commands.put(name, jc); } + public Map getCommands() { + return m_commands; + } + public String getParsedCommand() { return m_parsedCommand; } diff --git a/src/main/java/com/beust/jcommander/internal/Maps.java b/src/main/java/com/beust/jcommander/internal/Maps.java index 9b476d0..9238aaa 100644 --- a/src/main/java/com/beust/jcommander/internal/Maps.java +++ b/src/main/java/com/beust/jcommander/internal/Maps.java @@ -19,6 +19,7 @@ package com.beust.jcommander.internal; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; public class Maps { @@ -26,4 +27,9 @@ public class Maps { public static Map newHashMap() { return new HashMap(); } + + public static Map newLinkedHashMap() { + return new LinkedHashMap(); + } + } -- cgit v1.2.3 From d4b17eda61dbfe4d3c04e4761f0368eedf145349 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 4 Sep 2010 08:18:37 -0700 Subject: Now working with JDK5 --- src/main/java/com/beust/jcommander/JCommander.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f0c7d5a..5df0806 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -459,6 +459,7 @@ public class JCommander { // // Password option, use the Console to retrieve the password // + checkJdk6(); Console console = System.console(); if (console == null) { throw new ParameterException("No console is available to get parameter " + a); @@ -545,6 +546,17 @@ public class JCommander { } } + /** + * Aborts if we're not using Java 6. + */ + private void checkJdk6() { + try { + getClass().getClassLoader().loadClass("java.io.Console"); + } catch (ClassNotFoundException e) { + throw new ParameterException("The password option is only available with Java 6."); + } + } + private String[] subArray(String[] args, int index) { int l = args.length - index; String[] result = new String[l]; -- cgit v1.2.3 From ed891ffa6a8894150718d11df446269365bed216 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 4 Sep 2010 20:10:17 -0700 Subject: Now working with Java 5 --- src/main/java/com/beust/jcommander/JCommander.java | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5df0806..00405b1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -25,13 +25,13 @@ import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; import java.io.BufferedReader; -import java.io.Console; import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; @@ -459,13 +459,7 @@ public class JCommander { // // Password option, use the Console to retrieve the password // - checkJdk6(); - Console console = System.console(); - if (console == null) { - throw new ParameterException("No console is available to get parameter " + a); - } - System.out.print("Value for " + a + " (" + pd.getDescription() + "):"); - char[] password = console.readPassword(); + char[] password = readPassword(pd.getDescription()); pd.addValue(new String(password)); } else { // @@ -547,12 +541,18 @@ public class JCommander { } /** - * Aborts if we're not using Java 6. + * Invoke Console.readPassword through reflection to avoid depending + * on Java 6. */ - private void checkJdk6() { + private char[] readPassword(String description) { try { - getClass().getClassLoader().loadClass("java.io.Console"); - } catch (ClassNotFoundException e) { + Method consoleMethod = System.class.getDeclaredMethod("console", new Class[0]); + Object console = consoleMethod.invoke(null, new Object[0]); + Method readPassword = console.getClass().getDeclaredMethod("readPassword", new Class[0]); + System.out.print(description + ": "); + return (char[]) readPassword.invoke(console, new Object[0]); + } catch (Throwable t) { + t.printStackTrace(); throw new ParameterException("The password option is only available with Java 6."); } } -- cgit v1.2.3 From 69ae0501cf8ff817ca75231568cc12d46a71c9d0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 6 Sep 2010 07:16:55 -0700 Subject: Restored password support for Java5. --- src/main/java/com/beust/jcommander/JCommander.java | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 00405b1..bea5853 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -27,6 +27,7 @@ import com.beust.jcommander.internal.Maps; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.io.InputStreamReader; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -545,15 +546,30 @@ public class JCommander { * on Java 6. */ private char[] readPassword(String description) { + System.out.print(description + ": "); try { Method consoleMethod = System.class.getDeclaredMethod("console", new Class[0]); Object console = consoleMethod.invoke(null, new Object[0]); Method readPassword = console.getClass().getDeclaredMethod("readPassword", new Class[0]); - System.out.print(description + ": "); return (char[]) readPassword.invoke(console, new Object[0]); } catch (Throwable t) { - t.printStackTrace(); - throw new ParameterException("The password option is only available with Java 6."); + return readLine(description); + } + } + + /** + * Read a line from stdin (used when java.io.Console is not available) + */ + private char[] readLine(String description) { + try { + InputStreamReader isr = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(isr); + String result = in.readLine(); + in.close(); + isr.close(); + return result.toCharArray(); + } catch (IOException e) { + throw new ParameterException(e); } } -- cgit v1.2.3 From 8a59ec24df3a94036e1fdfdafe9608256158ef74 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 9 Sep 2010 12:50:40 -0700 Subject: Added \n after the option display. --- src/main/java/com/beust/jcommander/JCommander.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bea5853..5acdc7e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -694,7 +694,7 @@ public class JCommander { if (m_mainParameterAnnotation != null) { out.append(" " + m_mainParameterAnnotation.description() + "\n"); } - out.append(" Options:"); + out.append(" Options:\n"); // // Align the descriptions at the "longestName" column @@ -732,7 +732,8 @@ public class JCommander { + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + s(spaceCount) + pd.getDescription()); Object def = pd.getDefault(); - if (def != null) out.append(" (default: " + def + ")"); out.append("\n"); + if (def != null) out.append(" (default: " + def + ")"); + out.append("\n"); } // -- cgit v1.2.3 From a6e4abdbab416a28753abf76af5511bcd35753e9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 1 Oct 2010 11:42:59 -0700 Subject: Fixed: JCommander would sometimes just print a stack trace and continue, now rethrowing. --- src/main/java/com/beust/jcommander/JCommander.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5acdc7e..615b638 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -835,14 +835,12 @@ public class JCommander { String optionName = names.length > 0 ? names[0] : "[Main class]"; converter = instantiateConverter(optionName, converterClass); result = converter.convert(value); - } catch (IllegalArgumentException e) { - e.printStackTrace(); } catch (InstantiationException e) { - e.printStackTrace(); + throw new ParameterException(e); } catch (IllegalAccessException e) { - e.printStackTrace(); + throw new ParameterException(e); } catch (InvocationTargetException e) { - e.printStackTrace(); + throw new ParameterException(e); } return result; -- cgit v1.2.3 From e5799d36df3ceddb4b71b5f786e343c1c1e0d027 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 11 Oct 2010 11:17:20 -0700 Subject: Fixed ArrayIndexOutOfBoundsException. --- src/main/java/com/beust/jcommander/JCommander.java | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 615b638..0175a78 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -480,16 +480,20 @@ public class JCommander { int arity = pd.getParameter().arity(); int n = (arity != -1 ? arity : 1); - int offset = "--".equals(args[i + 1]) ? 1 : 0; - - if (i + n < args.length) { - for (int j = 1; j <= n; j++) { - pd.addValue(trim(args[i + j + offset])); - m_requiredFields.remove(pd.getField()); + if (i < args.length - 1) { + int offset = "--".equals(args[i + 1]) ? 1 : 0; + + if (i + n < args.length) { + for (int j = 1; j <= n; j++) { + pd.addValue(trim(args[i + j + offset])); + m_requiredFields.remove(pd.getField()); + } + i += n + offset; + } else { + throw new ParameterException(n + " parameters expected after " + arg); } - i += n + offset; } else { - throw new ParameterException(n + " parameters expected after " + arg); + throw new ParameterException("Expected a value after parameter " + arg); } } } -- cgit v1.2.3 From 1c5e7d362685371709595fe3d2e65ceadbdfcffc Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 11 Oct 2010 11:27:30 -0700 Subject: Disable new tests because TestNG depends on the older version of JCommander. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0175a78..9f9bcc9 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -490,7 +490,7 @@ public class JCommander { } i += n + offset; } else { - throw new ParameterException(n + " parameters expected after " + arg); + throw new ParameterException("Expected " + n + " values after " + arg); } } else { throw new ParameterException("Expected a value after parameter " + arg); -- cgit v1.2.3 From b828856eb3f2d04ebc118babb4068419fce5b3bd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 27 Nov 2010 10:12:14 -0800 Subject: Added: Boolean parameters with arity 0 (e.g. "foo -debug") --- src/main/java/com/beust/jcommander/JCommander.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9f9bcc9..0d6d48c 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -480,7 +480,14 @@ public class JCommander { int arity = pd.getParameter().arity(); int n = (arity != -1 ? arity : 1); - if (i < args.length - 1) { + // Special case for boolean parameters of arity 0 + if (n == 0 && + (Boolean.class.isAssignableFrom(fieldType) + || boolean.class.isAssignableFrom(fieldType))) { + pd.addValue("true"); + m_requiredFields.remove(pd.getField()); + } + else if (i < args.length - 1) { int offset = "--".equals(args[i + 1]) ? 1 : 0; if (i + n < args.length) { -- cgit v1.2.3 From 0dcc308f1c08b831376a3e153e2a1ed1a6166697 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 27 Nov 2010 12:53:20 -0800 Subject: Better usage(). Now sorting correctly and aligning -- options on the same column. --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++++- src/main/java/com/beust/jcommander/ParameterDescription.java | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0d6d48c..fe4c60a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -688,6 +688,10 @@ public class JCommander { System.out.println(sb.toString()); } + private String cleanUpNames(String names) { + return names.replace("-", "").replace(" ", "").toLowerCase(); + } + /** * Store the help in the passed string builder. */ @@ -729,7 +733,7 @@ public class JCommander { Collections.sort(sorted, new Comparator() { @Override public int compare(ParameterDescription arg0, ParameterDescription arg1) { - return arg0.getNames().toLowerCase().compareTo(arg1.getNames().toLowerCase()); + return cleanUpNames(arg0.getNames()).compareTo(cleanUpNames(arg1.getNames())); } }); diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index f265cae..169f20c 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -111,9 +111,11 @@ public class ParameterDescription { public String getNames() { StringBuilder sb = new StringBuilder(); - for (int i = 0; i < m_parameterAnnotation.names().length; i++) { + String[] names = m_parameterAnnotation.names(); + for (int i = 0; i < names.length; i++) { if (i > 0) sb.append(", "); - sb.append(m_parameterAnnotation.names()[i]); + if (names.length == 1 && names[i].startsWith("--")) sb.append(" "); + sb.append(names[i]); } return sb.toString(); } -- cgit v1.2.3 From a0f0aae9343685b767d6b7e11b399276f90f47e7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 27 Nov 2010 15:58:40 -0800 Subject: Better formatting of usage(). --- src/main/java/com/beust/jcommander/JCommander.java | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index fe4c60a..17bf452 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -743,9 +743,11 @@ public class JCommander { for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; + int start = out.length(); out.append(" " + (pd.getParameter().required() ? "* " : " ") - + pd.getNames() + s(spaceCount) + pd.getDescription()); + + pd.getNames() + s(spaceCount)); + wrapDescription(out, out.length() - start, pd.getDescription()); Object def = pd.getDefault(); if (def != null) out.append(" (default: " + def + ")"); out.append("\n"); @@ -767,6 +769,30 @@ public class JCommander { } } + private void wrapDescription(StringBuilder out, int indent, String description) { + int max = 79; + String[] words = description.split(" "); + int current = indent; + int i = 0; + while (i < words.length) { + String word = words[i]; + if (word.length() > max || current + word.length() <= max) { + out.append(word).append(" "); + current += word.length() + 1; + i++; + } else { + out.append("\n").append(spaces(indent)); + current = indent; + } + } + } + + private String spaces(int indent) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < indent; i++) sb.append(" "); + return sb.toString(); + } + /** * @return a Collection of all the @Parameter annotations found on the * target class. This can be used to display the usage() in a different -- cgit v1.2.3 From 1860b2add066a6e87b16ee80a57fe8099983e2b9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 27 Nov 2010 16:00:39 -0800 Subject: Minor fix. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 17bf452..6677e54 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -757,7 +757,7 @@ public class JCommander { // If commands were specified, show them as well // if (hasCommands) { - out.append(" Commands:\n"); + out.append("\n Commands:\n"); // The magic value 3 is the number of spaces between the name of the option // and its description int ln = longestName(m_commands.keySet()) + 3; @@ -777,7 +777,7 @@ public class JCommander { while (i < words.length) { String word = words[i]; if (word.length() > max || current + word.length() <= max) { - out.append(word).append(" "); + out.append(" ").append(word); current += word.length() + 1; i++; } else { -- cgit v1.2.3 From 28fde86d17ba423d09157646eff2339ff462c677 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 28 Nov 2010 10:10:42 -0800 Subject: Better usage formatting. --- src/main/java/com/beust/jcommander/JCommander.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 6677e54..5b38fb3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -747,9 +747,10 @@ public class JCommander { out.append(" " + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + s(spaceCount)); - wrapDescription(out, out.length() - start, pd.getDescription()); + int indent = out.length() - start; + wrapDescription(out, indent, pd.getDescription()); Object def = pd.getDefault(); - if (def != null) out.append(" (default: " + def + ")"); + if (def != null) out.append("\n" + spaces(indent + 1)).append("Default: " + def); out.append("\n"); } @@ -757,7 +758,7 @@ public class JCommander { // If commands were specified, show them as well // if (hasCommands) { - out.append("\n Commands:\n"); + out.append(" Commands:\n"); // The magic value 3 is the number of spaces between the name of the option // and its description int ln = longestName(m_commands.keySet()) + 3; -- cgit v1.2.3 From 9c170b3038460fde4999afc7af7bb5d31e3f1e47 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 28 Nov 2010 12:00:17 -0800 Subject: Alphabetical usage. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- .../java/com/beust/jcommander/ParameterDescription.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5b38fb3..e3322ea 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -732,8 +732,8 @@ public class JCommander { // Collections.sort(sorted, new Comparator() { @Override - public int compare(ParameterDescription arg0, ParameterDescription arg1) { - return cleanUpNames(arg0.getNames()).compareTo(cleanUpNames(arg1.getNames())); + public int compare(ParameterDescription p0, ParameterDescription p1) { + return p0.getLongestName().compareTo(p1.getLongestName()); } }); diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 169f20c..58ed485 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -38,6 +38,8 @@ public class ParameterDescription { private String m_description; private JCommander m_jCommander; private Object m_default; + /** Longest of the names(), used to present usage() alphabetically */ + private String m_longestName = ""; public ParameterDescription(Object object, Parameter annotation, Field field, ResourceBundle bundle, JCommander jc) { @@ -91,11 +93,19 @@ public class ParameterDescription { } } + for (String name : annotation.names()) { + if (name.length() > m_longestName.length()) m_longestName = name; + } + try { m_default = m_field.get(m_object); } catch (Exception e) { - } - } + } + } + + public String getLongestName() { + return m_longestName; + } public Object getDefault() { return m_default; -- cgit v1.2.3 From c1d51baff4fb68b90b2f9cdfea512c84ab94eb42 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 15 Dec 2010 09:49:08 -0800 Subject: Removed @Override to guarantee JDK 1.5 compilation. --- src/main/java/com/beust/jcommander/JCommander.java | 4 +--- src/main/java/com/beust/jcommander/converters/BooleanConverter.java | 1 - .../java/com/beust/jcommander/converters/CommaSeparatedConverter.java | 1 - src/main/java/com/beust/jcommander/converters/FileConverter.java | 1 - src/main/java/com/beust/jcommander/converters/IntegerConverter.java | 1 - src/main/java/com/beust/jcommander/converters/LongConverter.java | 1 - src/main/java/com/beust/jcommander/converters/NoConverter.java | 1 - src/main/java/com/beust/jcommander/converters/StringConverter.java | 1 - .../beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java | 1 - 9 files changed, 1 insertion(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e3322ea..43198dc 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -486,8 +486,7 @@ public class JCommander { || boolean.class.isAssignableFrom(fieldType))) { pd.addValue("true"); m_requiredFields.remove(pd.getField()); - } - else if (i < args.length - 1) { + } else if (i < args.length - 1) { int offset = "--".equals(args[i + 1]) ? 1 : 0; if (i + n < args.length) { @@ -731,7 +730,6 @@ public class JCommander { // Sort the options // Collections.sort(sorted, new Comparator() { - @Override public int compare(ParameterDescription p0, ParameterDescription p1) { return p0.getLongestName().compareTo(p1.getLongestName()); } diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java index 35188ca..5126d22 100644 --- a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java @@ -31,7 +31,6 @@ public class BooleanConverter extends BaseConverter { super(optionName); } - @Override public Boolean convert(String value) { if ("false".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)) { return Boolean.parseBoolean(value); diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java index 033138a..b719bd4 100644 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java @@ -30,7 +30,6 @@ import java.util.List; */ public class CommaSeparatedConverter implements IStringConverter> { - @Override public List convert(String value) { return Arrays.asList(value.split(",")); } diff --git a/src/main/java/com/beust/jcommander/converters/FileConverter.java b/src/main/java/com/beust/jcommander/converters/FileConverter.java index ea4d9ba..c18b575 100644 --- a/src/main/java/com/beust/jcommander/converters/FileConverter.java +++ b/src/main/java/com/beust/jcommander/converters/FileConverter.java @@ -29,7 +29,6 @@ import java.io.File; */ public class FileConverter implements IStringConverter { - @Override public File convert(String value) { return new File(value); } diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java index be38126..53d1119 100644 --- a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java +++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java @@ -31,7 +31,6 @@ public class IntegerConverter extends BaseConverter { super(optionName); } - @Override public Integer convert(String value) { try { return Integer.parseInt(value); diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java index bbfa0cf..863956b 100644 --- a/src/main/java/com/beust/jcommander/converters/LongConverter.java +++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java @@ -31,7 +31,6 @@ public class LongConverter extends BaseConverter { super(optionName); } - @Override public Long convert(String value) { try { return Long.parseLong(value); diff --git a/src/main/java/com/beust/jcommander/converters/NoConverter.java b/src/main/java/com/beust/jcommander/converters/NoConverter.java index c670258..618daf9 100644 --- a/src/main/java/com/beust/jcommander/converters/NoConverter.java +++ b/src/main/java/com/beust/jcommander/converters/NoConverter.java @@ -27,7 +27,6 @@ import com.beust.jcommander.IStringConverter; */ public class NoConverter implements IStringConverter { - @Override public String convert(String value) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/com/beust/jcommander/converters/StringConverter.java b/src/main/java/com/beust/jcommander/converters/StringConverter.java index 1dce8b8..ea1ae38 100644 --- a/src/main/java/com/beust/jcommander/converters/StringConverter.java +++ b/src/main/java/com/beust/jcommander/converters/StringConverter.java @@ -27,7 +27,6 @@ import com.beust.jcommander.IStringConverter; */ public class StringConverter implements IStringConverter { - @Override public String convert(String value) { return value; } diff --git a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java index 47eeedb..d5401a1 100644 --- a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java +++ b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java @@ -58,7 +58,6 @@ public class PropertyFileDefaultProvider implements IDefaultProvider { } } - @Override public String getDefaultValueFor(String optionName) { int index = 0; while (index < optionName.length() && ! Character.isLetterOrDigit(optionName.charAt(index))) { -- cgit v1.2.3 From f2cd60c1f0e475201b9d24b486df920ff1d02ac5 Mon Sep 17 00:00:00 2001 From: Russell Egan Date: Thu, 23 Dec 2010 14:37:30 -0500 Subject: parse() should check if createDescriptions was already called When using main parameters, createDescriptions can't be called twice, but it is possible to do so by using combinations of usage() and parse() --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 43198dc..d9e674d 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -183,7 +183,7 @@ public class JCommander { sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray()))); p(sb.toString()); - createDescriptions(); + if (m_descriptions == null) createDescriptions(); initializeDefaultValues(); parseValues(expandArgs(args)); validateOptions(); -- cgit v1.2.3 From dae46a1c4166085b56a78669050dc19938735a41 Mon Sep 17 00:00:00 2001 From: Russell Egan Date: Thu, 23 Dec 2010 14:38:47 -0500 Subject: Added a constructor which takes a resource bundle, but doesn't parse immediately. This is useful when you want to interrogate some options even when required options are missing. --- src/main/java/com/beust/jcommander/JCommander.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d9e674d..427332b 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -136,6 +136,14 @@ public class JCommander { init(object, null); } + /** + * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param bundle The bundle to use for the descriptions. Can be null. + */ + public JCommander(Object object, ResourceBundle bundle) { + init(object, bundle); + } + /** * @param object The arg object expected to contain {@link @Parameter} annotations. * @param bundle The bundle to use for the descriptions. Can be null. -- cgit v1.2.3 From dc01e7c94224b7a9c2b07af35404fb988732a0ad Mon Sep 17 00:00:00 2001 From: Patrick Linskey Date: Sat, 1 Jan 2011 12:53:16 -0800 Subject: no-args constructor for cases where there is no top-level param object. This might happen if all options are destined to be parsed by commands, which are added after instance construction. --- src/main/java/com/beust/jcommander/JCommander.java | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 427332b..c6ca64a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -66,7 +66,7 @@ public class JCommander { /** * The objects that contain fields annotated with @Parameter. */ - private List m_objects; + private List m_objects = Lists.newArrayList(); /** * This field will contain whatever command line parameter is not an option. @@ -129,11 +129,17 @@ public class JCommander { CONVERTER_FACTORIES.add(new DefaultConverterFactory()); }; + /** + * Creates a new un-configured JCommander object. + */ + public JCommander() { + } + /** * @param object The arg object expected to contain {@link @Parameter} annotations. */ public JCommander(Object object) { - init(object, null); + addObject(object); } /** @@ -141,7 +147,8 @@ public class JCommander { * @param bundle The bundle to use for the descriptions. Can be null. */ public JCommander(Object object, ResourceBundle bundle) { - init(object, bundle); + addObject(object); + setDescriptionsBundle(bundle); } /** @@ -150,7 +157,8 @@ public class JCommander { * @param args The arguments to parse (optional). */ public JCommander(Object object, ResourceBundle bundle, String... args) { - init(object, bundle); + addObject(object); + setDescriptionsBundle(bundle); parse(args); } @@ -159,13 +167,20 @@ public class JCommander { * @param args The arguments to parse (optional). */ public JCommander(Object object, String... args) { - init(object, null); + addObject(object); parse(args); } - private void init(Object object, ResourceBundle bundle) { - m_bundle = bundle; - m_objects = Lists.newArrayList(); + /** + * Adds the provided arg object to the set of objects that this commander + * will parse arguments into. + * + * @param object The arg object expected to contain {@link Parameter} + * annotations. If object is an array or is {@link Iterable}, + * the child objects will be added instead. + */ + // declared final since this is invoked from constructors + public final void addObject(Object object) { if (object instanceof Iterable) { // Iterable for (Object o : (Iterable) object) { @@ -180,7 +195,15 @@ public class JCommander { // Single object m_objects.add(object); } + } + /** + * Sets the {@link ResourceBundle} to use for looking up descriptions. + * Set this to null to use description text directly. + */ + // declared final since this is invoked from constructors + public final void setDescriptionsBundle(ResourceBundle bundle) { + m_bundle = bundle; } /** -- cgit v1.2.3 From e5012b124d36eda59ffb69ca42dcd89637279716 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 4 Jan 2011 12:41:01 -0800 Subject: Removed extra spaces. --- src/main/java/com/beust/jcommander/JCommander.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c6ca64a..b03b25a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -130,7 +130,7 @@ public class JCommander { }; /** - * Creates a new un-configured JCommander object. + * Creates a new un-configured JCommander object. */ public JCommander() { } @@ -173,10 +173,10 @@ public class JCommander { /** * Adds the provided arg object to the set of objects that this commander - * will parse arguments into. + * will parse arguments into. * - * @param object The arg object expected to contain {@link Parameter} - * annotations. If object is an array or is {@link Iterable}, + * @param object The arg object expected to contain {@link Parameter} + * annotations. If object is an array or is {@link Iterable}, * the child objects will be added instead. */ // declared final since this is invoked from constructors -- cgit v1.2.3 From 31c421a62bc1c2e90b4a2c30719d677f73d086fd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 4 Jan 2011 15:59:58 -0800 Subject: Removed Javadoc warnings. --- src/main/java/com/beust/jcommander/JCommander.java | 24 +++++++++------------- .../com/beust/jcommander/ParameterDescription.java | 3 --- .../java/com/beust/jcommander/ResourceBundle.java | 2 +- 3 files changed, 11 insertions(+), 18 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b03b25a..46f3b9b 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -49,9 +49,9 @@ import java.util.ResourceBundle; * values and a few other helper methods, such as usage(). * * The object(s) you pass in the constructor are expected to have one or more - * @Parameter annotations on them. You can pass either a single object, an array of objects + * \@Parameter annotations on them. You can pass either a single object, an array of objects * or an instance of Iterable. In the case of an array or Iterable, JCommander will collect - * the @Parameter annotations from all the objects passed in parameter. + * the \@Parameter annotations from all the objects passed in parameter. * * @author cbeust */ @@ -136,14 +136,14 @@ public class JCommander { } /** - * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param object The arg object expected to contain {@link Parameter} annotations. */ public JCommander(Object object) { addObject(object); } /** - * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param object The arg object expected to contain {@link Parameter} annotations. * @param bundle The bundle to use for the descriptions. Can be null. */ public JCommander(Object object, ResourceBundle bundle) { @@ -152,7 +152,7 @@ public class JCommander { } /** - * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param object The arg object expected to contain {@link Parameter} annotations. * @param bundle The bundle to use for the descriptions. Can be null. * @param args The arguments to parse (optional). */ @@ -163,7 +163,7 @@ public class JCommander { } /** - * @param object The arg object expected to contain {@link @Parameter} annotations. + * @param object The arg object expected to contain {@link Parameter} annotations. * @param args The arguments to parse (optional). */ public JCommander(Object object, String... args) { @@ -407,7 +407,7 @@ public class JCommander { } /** - * Create the ParameterDescriptions for all the @Parameter found. + * Create the ParameterDescriptions for all the \@Parameter found. */ private void createDescriptions() { m_descriptions = Maps.newHashMap(); @@ -718,10 +718,6 @@ public class JCommander { System.out.println(sb.toString()); } - private String cleanUpNames(String names) { - return names.replace("-", "").replace(" ", "").toLowerCase(); - } - /** * Store the help in the passed string builder. */ @@ -824,7 +820,7 @@ public class JCommander { } /** - * @return a Collection of all the @Parameter annotations found on the + * @return a Collection of all the \@Parameter annotations found on the * target class. This can be used to display the usage() in a different * format (e.g. HTML). */ @@ -863,8 +859,8 @@ public class JCommander { } /** - * @param type The class of the field - * @param annotation The annotation + * @param field The field + * @param type The type of the actual parameter * @param value The value to convert */ public Object convertValue(Field field, Class type, String value) { diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 58ed485..a2232f6 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -162,8 +162,6 @@ public class ParameterDescription { /** * Add the specified value to the field. First look up any field converter, then * any type converter, and if we can't find any, throw an exception. - * - * @param markAdded if true, mark this parameter as assigned */ public void addValue(String value, boolean isDefault) { p("Adding " + (isDefault ? "default " : "") + "value:" + value @@ -178,7 +176,6 @@ public class ParameterDescription { if (! isDefault) m_assigned = true; Object convertedValue = m_jCommander.convertValue(this, value); boolean isCollection = Collection.class.isAssignableFrom(type); - boolean isMainParameter = m_parameterAnnotation.names().length == 0; try { if (isCollection) { diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java index 8309216..279fa6d 100644 --- a/src/main/java/com/beust/jcommander/ResourceBundle.java +++ b/src/main/java/com/beust/jcommander/ResourceBundle.java @@ -24,7 +24,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * @deprecated, use @Parameters + * @deprecated use @Parameters * * @author cbeust */ -- cgit v1.2.3 From e2d8da7b584b6a13c23de32ce2df0799a4d3513d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 24 Jan 2011 14:01:29 -0800 Subject: Fixed: NPE with calling getCommandDescription() of an unknown command --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 46f3b9b..f715620 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -702,6 +702,10 @@ public class JCommander { */ public String getCommandDescription(String commandName) { JCommander jc = m_commands.get(commandName); + if (jc == null) { + throw new ParameterException("Asking description for unknown command: " + commandName); + } + Parameters p = jc.getObjects().get(0).getClass().getAnnotation(Parameters.class); String result = jc.getMainParameterDescription(); if (p != null) result = p.commandDescription(); -- cgit v1.2.3 From 5f94fa3f279131d63e55a68bf16b4dd632c643f6 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 24 Jan 2011 14:21:01 -0800 Subject: Don't display "Options:" if none were defined. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f715620..f7532a2 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -739,7 +739,6 @@ public class JCommander { if (m_mainParameterAnnotation != null) { out.append(" " + m_mainParameterAnnotation.description() + "\n"); } - out.append(" Options:\n"); // // Align the descriptions at the "longestName" column @@ -769,6 +768,7 @@ public class JCommander { // // Display all the names and descriptions // + if (sorted.size() > 0) out.append(" Options:\n"); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; -- cgit v1.2.3 From 804498ec24662928bf06efcee6584d55fca3d898 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 24 Jan 2011 14:44:15 -0800 Subject: Double check that the type of a main parameter is a List. --- src/main/java/com/beust/jcommander/JCommander.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f7532a2..1167034 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -629,7 +629,7 @@ public class JCommander { /** * @return the field that's meant to receive all the parameters that are not options. * - * @param arg the arg that we're about to add (only passed here to ouput a meaningful + * @param arg the arg that we're about to add (only passed here to output a meaningful * error message). */ private List getMainParameter(String arg) { @@ -639,10 +639,13 @@ public class JCommander { } try { - @SuppressWarnings("unchecked") - List result = (List) m_mainParameterField.get(m_mainParameterObject); + List result = (List) m_mainParameterField.get(m_mainParameterObject); if (result == null) { result = Lists.newArrayList(); + if (! List.class.isAssignableFrom(m_mainParameterField.getType())) { + throw new ParameterException("Main parameter field " + m_mainParameterField + + " needs to be of type List, not " + m_mainParameterField.getType()); + } m_mainParameterField.set(m_mainParameterObject, result); } return result; -- cgit v1.2.3 From c512c633a76a8bfe5a8eda8c6198cce7af4c5eaf Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 24 Jan 2011 14:52:47 -0800 Subject: Fixed OOM reported by huxi. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1167034..e4ab6a0 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -812,11 +812,11 @@ public class JCommander { if (word.length() > max || current + word.length() <= max) { out.append(" ").append(word); current += word.length() + 1; - i++; } else { - out.append("\n").append(spaces(indent)); + out.append("\n").append(spaces(indent + 1)).append(word); current = indent; } + i++; } } -- cgit v1.2.3 From 26fa1a86fa9c35b50735e4bcfca1c9ea7919fae1 Mon Sep 17 00:00:00 2001 From: sclasen Date: Mon, 28 Feb 2011 12:45:30 -0800 Subject: call createDescriptions in single arg constructor and make getMaimParamterDescription public --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e4ab6a0..79d2a85 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -140,6 +140,7 @@ public class JCommander { */ public JCommander(Object object) { addObject(object); + createDescriptions(); } /** @@ -655,7 +656,7 @@ public class JCommander { } } - private String getMainParameterDescription() { + public String getMainParameterDescription() { if (m_descriptions == null) createDescriptions(); return m_mainParameterAnnotation != null ? m_mainParameterAnnotation.description() : null; -- cgit v1.2.3 From 498e8bdb06b2926085c06a9d64c4846872569a1c Mon Sep 17 00:00:00 2001 From: sclasen Date: Fri, 4 Mar 2011 16:34:03 -0800 Subject: make it possible to do partial parsing of arguments, and get back info on what parsed successfully --- src/main/java/com/beust/jcommander/JCommander.java | 45 ++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 79d2a85..1265b30 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -47,12 +47,12 @@ import java.util.ResourceBundle; * The main class for JCommander. It's responsible for parsing the object that contains * all the annotated fields, parse the command line and assign the fields with the correct * values and a few other helper methods, such as usage(). - * + * * The object(s) you pass in the constructor are expected to have one or more - * \@Parameter annotations on them. You can pass either a single object, an array of objects + * \@Parameter annotations on them. You can pass either a single object, an array of objects * or an instance of Iterable. In the case of an array or Iterable, JCommander will collect * the \@Parameter annotations from all the objects passed in parameter. - * + * * @author cbeust */ public class JCommander { @@ -221,6 +221,27 @@ public class JCommander { validateOptions(); } + public void parseWithoutValidation(String... args) { + StringBuilder sb = new StringBuilder("Parsing \""); + sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray()))); + p(sb.toString()); + + if (m_descriptions == null) createDescriptions(); + initializeDefaultValues(); + parseValues(expandArgs(args)); + } + + public List getParsedParameterDescriptions(){ + List descriptions = new ArrayList(); + descriptions.addAll(m_descriptions.values()); + if(m_mainParameterDescription != null){ + descriptions.add(m_mainParameterDescription); + } + return descriptions; + } + + + private StringBuilder join(Object[] args) { StringBuilder result = new StringBuilder(); for (int i = 0; i < args.length; i++) { @@ -258,12 +279,12 @@ public class JCommander { } } } - + /** * Expand the command line parameters to take @ parameters into account. * When @ is encountered, the content of the file that follows is inserted * in the command line. - * + * * @param originalArgv the original command line parameters * @return the new and enriched command line parameters */ @@ -367,7 +388,7 @@ public class JCommander { /** * Reads the file specified by filename and returns the file content as a string. * End of lines are replaced by a space. - * + * * @param fileName the command line filename * @return the file content as a string. */ @@ -499,7 +520,7 @@ public class JCommander { // Regular option // Class fieldType = pd.getField().getType(); - + // Boolean, set to true as soon as we see it, unless it specified // an arity of 1, in which case we need to read the next value if ((fieldType == boolean.class || fieldType == Boolean.class) @@ -551,7 +572,7 @@ public class JCommander { List mp = getMainParameter(arg); String value = arg; Object convertedValue = value; - + if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); Type cls = p.getActualTypeArguments()[0]; @@ -559,7 +580,7 @@ public class JCommander { convertedValue = convertValue(m_mainParameterField, (Class) cls, value); } } - + m_mainParameterDescription.setAssigned(true); mp.add(convertedValue); } @@ -591,7 +612,7 @@ public class JCommander { System.out.print(description + ": "); try { Method consoleMethod = System.class.getDeclaredMethod("console", new Class[0]); - Object console = consoleMethod.invoke(null, new Object[0]); + Object console = consoleMethod.invoke(null, new Object[0]); Method readPassword = console.getClass().getDeclaredMethod("readPassword", new Class[0]); return (char[]) readPassword.invoke(console, new Object[0]); } catch (Throwable t) { @@ -629,7 +650,7 @@ public class JCommander { /** * @return the field that's meant to receive all the parameters that are not options. - * + * * @param arg the arg that we're about to add (only passed here to output a meaningful * error message). */ @@ -744,7 +765,7 @@ public class JCommander { out.append(" " + m_mainParameterAnnotation.description() + "\n"); } - // + // // Align the descriptions at the "longestName" column // int longestName = 0; -- cgit v1.2.3 From cf51b03416fc313fadfc6a427c23f37fb282f24c Mon Sep 17 00:00:00 2001 From: sclasen Date: Mon, 7 Mar 2011 16:39:32 -0800 Subject: after parsing, set the assigned flag for the parameterDescriptions in m_fields that have been assigned, add a getMainParameter method that returns the main ParamaterDescription obj --- src/main/java/com/beust/jcommander/JCommander.java | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1265b30..5fb47ba 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -231,17 +231,6 @@ public class JCommander { parseValues(expandArgs(args)); } - public List getParsedParameterDescriptions(){ - List descriptions = new ArrayList(); - descriptions.addAll(m_descriptions.values()); - if(m_mainParameterDescription != null){ - descriptions.add(m_mainParameterDescription); - } - return descriptions; - } - - - private StringBuilder join(Object[] args) { StringBuilder result = new StringBuilder(); for (int i = 0; i < args.length; i++) { @@ -602,6 +591,14 @@ public class JCommander { } i++; } + + //Flag the parameter descriptions held in field as assigned + for (ParameterDescription parameterDescription : m_descriptions.values()) { + if(parameterDescription.isAssigned()){ + m_fields.get(parameterDescription.getField()).setAssigned(true); + } + } + } /** @@ -857,6 +854,13 @@ public class JCommander { return new ArrayList(m_fields.values()); } + /** + * @return the main parameter description or null if none is defined. + */ + public ParameterDescription getMainParameter(){ + return m_mainParameterDescription; + } + private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[JCommander] " + string); -- cgit v1.2.3 From b2367c03a3dcb1bead3b34926d958fc94d9c0028 Mon Sep 17 00:00:00 2001 From: sclasen Date: Tue, 8 Mar 2011 12:21:18 -0800 Subject: fix typo in comment --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5fb47ba..e7ff287 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -592,7 +592,7 @@ public class JCommander { i++; } - //Flag the parameter descriptions held in field as assigned + //Flag the parameter descriptions held in m_fields as assigned for (ParameterDescription parameterDescription : m_descriptions.values()) { if(parameterDescription.isAssigned()){ m_fields.get(parameterDescription.getField()).setAssigned(true); -- cgit v1.2.3 From cfbeb8905f1166e5fd03624a34571d6ae5ab321d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 9 Mar 2011 11:24:15 -0800 Subject: First pass at implementing validators. --- .../com/beust/jcommander/IParameterValidator.java | 38 ++++++++++++++++++++ src/main/java/com/beust/jcommander/Parameter.java | 6 ++++ .../com/beust/jcommander/ParameterDescription.java | 21 ++++++++++-- .../beust/jcommander/validators/NoValidator.java | 35 +++++++++++++++++++ .../jcommander/validators/PositiveInteger.java | 40 ++++++++++++++++++++++ 5 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IParameterValidator.java create mode 100644 src/main/java/com/beust/jcommander/validators/NoValidator.java create mode 100644 src/main/java/com/beust/jcommander/validators/PositiveInteger.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IParameterValidator.java b/src/main/java/com/beust/jcommander/IParameterValidator.java new file mode 100644 index 0000000..19fee0d --- /dev/null +++ b/src/main/java/com/beust/jcommander/IParameterValidator.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2011 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander; + +/** + * The class used to validate parameters. + * + * @author Cedric Beust + */ +public interface IParameterValidator { + + /** + * Validate the parameter. + * + * @param name The name of the parameter (e.g. "-host"). + * @param value The value of the parameter that we need to validate + * + * @throws ParameterException Thrown if the value of the parameter is invalid. + */ + void validate(String name, String value) throws ParameterException; + +} diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 24fa469..7003f5d 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -21,6 +21,7 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; import com.beust.jcommander.converters.NoConverter; +import com.beust.jcommander.validators.NoValidator; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -72,4 +73,9 @@ public @interface Parameter { * If true, this parameter won't appear in the usage(). */ boolean hidden() default false; + + /** + * The validation class to use. + */ + Class validateWith() default NoValidator.class; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index a2232f6..281f190 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -20,6 +20,7 @@ package com.beust.jcommander; import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.validators.NoValidator; import java.lang.reflect.Field; import java.util.Collection; @@ -160,17 +161,31 @@ public class ParameterDescription { } /** - * Add the specified value to the field. First look up any field converter, then - * any type converter, and if we can't find any, throw an exception. + * Add the specified value to the field. First, validate the value if a + * validator was specified. Then look up any field converter, then any type + * converter, and if we can't find any, throw an exception. */ public void addValue(String value, boolean isDefault) { p("Adding " + (isDefault ? "default " : "") + "value:" + value + " to parameter:" + m_field.getName()); + String name = m_parameterAnnotation.names()[0]; if (m_assigned && ! isMultiOption()) { - throw new ParameterException("Can only specify option " + m_parameterAnnotation.names()[0] + throw new ParameterException("Can only specify option " + name + " once."); } + Class validator = m_parameterAnnotation.validateWith(); + if (validator != NoValidator.class) { + try { + p("Validating parameter:" + name + " value:" + value + " validator:" + validator); + validator.newInstance().validate(name, value); + } catch (InstantiationException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } catch (IllegalAccessException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } + } + Class type = m_field.getType(); if (! isDefault) m_assigned = true; diff --git a/src/main/java/com/beust/jcommander/validators/NoValidator.java b/src/main/java/com/beust/jcommander/validators/NoValidator.java new file mode 100644 index 0000000..f1b4df2 --- /dev/null +++ b/src/main/java/com/beust/jcommander/validators/NoValidator.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2011 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.validators; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +/** + * This is the default value of the validateWith attribute. + * + * @author Cedric Beust + */ +public class NoValidator implements IParameterValidator { + + public void validate(String parameterName, String parameterValue) + throws ParameterException { + } + +} diff --git a/src/main/java/com/beust/jcommander/validators/PositiveInteger.java b/src/main/java/com/beust/jcommander/validators/PositiveInteger.java new file mode 100644 index 0000000..7b5c1b7 --- /dev/null +++ b/src/main/java/com/beust/jcommander/validators/PositiveInteger.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2011 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.validators; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +/** + * A validator that makes sure the value of the parameter is a positive integer. + * + * @author Cedric Beust + */ +public class PositiveInteger implements IParameterValidator { + + public void validate(String name, String value) + throws ParameterException { + int n = Integer.parseInt(value); + if (n < 0) { + throw new ParameterException("Parameter " + name + + " should be positive (found " + value +")"); + } + } + +} -- cgit v1.2.3 From 344383cd3a0d67c900fb40dd7ba7d8a528798411 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 10:44:19 -0800 Subject: Dead code. --- src/main/java/com/beust/jcommander/JCommander.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 79d2a85..2b18236 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -898,10 +898,10 @@ public class JCommander { // converter = (IStringConverter) m_converterFactories.getConverter(type); // } - if (converterClass == null) { - throw new ParameterException("Don't know how to convert " + value - + " to type " + type + " (field: " + field.getName() + ")"); - } +// if (converterClass == null) { +// throw new ParameterException("Don't know how to convert " + value +// + " to type " + type + " (field: " + field.getName() + ")"); +// } IStringConverter converter; Object result = null; -- cgit v1.2.3 From ad383ae3f3e890856da4ae1d487bdcac5feab4b7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 10:44:32 -0800 Subject: Dead code. --- src/main/java/com/beust/jcommander/JCommander.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 2b18236..c7f921f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -884,9 +884,6 @@ public class JCommander { if (converterClass == null) { converterClass = StringConverter.class; } - if (converterClass == null && Collection.class.isAssignableFrom(type)) { - converterClass = StringConverter.class; - } // // // -- cgit v1.2.3 From 91b83b28a07d3ab0df7880b473e37b2b978c6a99 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 10:44:54 -0800 Subject: Suppress a few warnings. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 1 + src/main/java/com/beust/jcommander/ParameterException.java | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 281f190..210d0ba 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -51,6 +51,7 @@ public class ParameterDescription { * Find the resource bundle in the annotations. * @return */ + @SuppressWarnings("deprecation") private ResourceBundle findResourceBundle(Object o) { ResourceBundle result = null; diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java index 8bf5a20..3c0f588 100644 --- a/src/main/java/com/beust/jcommander/ParameterException.java +++ b/src/main/java/com/beust/jcommander/ParameterException.java @@ -18,6 +18,13 @@ package com.beust.jcommander; +/** + * The main exception that JCommand will throw when something goes wrong while + * parsing parameters. + * + * @author Cedric Beust + */ +@SuppressWarnings("serial") public class ParameterException extends RuntimeException { public ParameterException(Throwable t) { -- cgit v1.2.3 From 045653099e8e35ef1f05654b6b023cc8324c0ebf Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 10:45:11 -0800 Subject: Javadoc. --- src/main/java/com/beust/jcommander/ResourceBundle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java index 279fa6d..806ade8 100644 --- a/src/main/java/com/beust/jcommander/ResourceBundle.java +++ b/src/main/java/com/beust/jcommander/ResourceBundle.java @@ -26,7 +26,7 @@ import java.lang.annotation.Target; /** * @deprecated use @Parameters * - * @author cbeust + * @author Cedric Beust */ @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({ TYPE }) -- cgit v1.2.3 From d576340c4a1fe43ad63ac3dfb346ca4c90dde574 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 10:45:46 -0800 Subject: Introduced new MissingCommandException. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- .../beust/jcommander/MissingCommandException.java | 36 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/beust/jcommander/MissingCommandException.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c7f921f..2cbbac2 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -568,7 +568,7 @@ public class JCommander { // Command parsing // JCommander jc = m_commands.get(arg); - if (jc == null) throw new ParameterException("Expected a command, got " + arg); + if (jc == null) throw new MissingCommandException("Expected a command, got " + arg); m_parsedCommand = arg; // Found a valid command, ask it to parse the remainder of the arguments. diff --git a/src/main/java/com/beust/jcommander/MissingCommandException.java b/src/main/java/com/beust/jcommander/MissingCommandException.java new file mode 100644 index 0000000..1d572ab --- /dev/null +++ b/src/main/java/com/beust/jcommander/MissingCommandException.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander; + +/** + * Thrown when a command was expected. + * + * @author Cedric Beust + */ +@SuppressWarnings("serial") +public class MissingCommandException extends ParameterException { + + public MissingCommandException(String string) { + super(string); + } + + public MissingCommandException(Throwable t) { + super(t); + } +} -- cgit v1.2.3 From 8877f663e79381340b329180922d7ac448e26317 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 11:04:38 -0800 Subject: Fixed: Exception when using an @ file with empty lines between options. --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 2cbbac2..4209aa1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -381,7 +381,8 @@ public class JCommander { // Read through file one line at time. Print line # and line while ((line = bufRead.readLine()) != null) { - result.add(line); + // Allow empty lines in these at files + if (line.length() > 0) result.add(line); } bufRead.close(); -- cgit v1.2.3 From 6995afda6050f57d12bc08046755146e0de67de1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 10 Mar 2011 13:24:20 -0800 Subject: Some refactoring on top of sclasen's change. --- src/main/java/com/beust/jcommander/JCommander.java | 37 +++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 46fbffc..f96efff 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -208,20 +208,20 @@ public class JCommander { } /** - * Parse the command line parameters. + * Parse and validate the command line parameters. */ public void parse(String... args) { - StringBuilder sb = new StringBuilder("Parsing \""); - sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray()))); - p(sb.toString()); - - if (m_descriptions == null) createDescriptions(); - initializeDefaultValues(); - parseValues(expandArgs(args)); - validateOptions(); + parse(true /* validate */, args); } + /** + * Parse the command line parameters without validating them. + */ public void parseWithoutValidation(String... args) { + parse(false /* no validation */, args); + } + + private void parse(boolean validate, String... args) { StringBuilder sb = new StringBuilder("Parsing \""); sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray()))); p(sb.toString()); @@ -229,6 +229,7 @@ public class JCommander { if (m_descriptions == null) createDescriptions(); initializeDefaultValues(); parseValues(expandArgs(args)); + if (validate) validateOptions(); } private StringBuilder join(Object[] args) { @@ -593,12 +594,12 @@ public class JCommander { i++; } - //Flag the parameter descriptions held in m_fields as assigned - for (ParameterDescription parameterDescription : m_descriptions.values()) { - if(parameterDescription.isAssigned()){ - m_fields.get(parameterDescription.getField()).setAssigned(true); - } + // Mark the parameter descriptions held in m_fields as assigned + for (ParameterDescription parameterDescription : m_descriptions.values()) { + if (parameterDescription.isAssigned()) { + m_fields.get(parameterDescription.getField()).setAssigned(true); } + } } @@ -855,10 +856,10 @@ public class JCommander { return new ArrayList(m_fields.values()); } - /** - * @return the main parameter description or null if none is defined. - */ - public ParameterDescription getMainParameter(){ + /** + * @return the main parameter description or null if none is defined. + */ + public ParameterDescription getMainParameter() { return m_mainParameterDescription; } -- cgit v1.2.3 From a9656e4788b44f97aff3c480a4292245c588fed3 Mon Sep 17 00:00:00 2001 From: sclasen Date: Mon, 11 Apr 2011 14:49:16 -0700 Subject: let converterfactories have the chance to override existing defaults --- src/main/java/com/beust/jcommander/JCommander.java | 9 ++++-- .../java/com/beust/jcommander/internal/Lists.java | 33 ++++++++++++++-------- 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f96efff..104f6ee 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -40,9 +40,12 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.LinkedList; import java.util.Map; import java.util.ResourceBundle; + + /** * The main class for JCommander. It's responsible for parsing the object that contains * all the annotated fields, parse the command line and assign the fields with the correct @@ -123,10 +126,10 @@ public class JCommander { /** * The factories used to look up string converters. */ - private static List CONVERTER_FACTORIES = Lists.newArrayList(); + private static LinkedList CONVERTER_FACTORIES = Lists.newLinkedList(); static { - CONVERTER_FACTORIES.add(new DefaultConverterFactory()); + CONVERTER_FACTORIES.addFirst(new DefaultConverterFactory()); }; /** @@ -877,7 +880,7 @@ public class JCommander { } public void addConverterFactory(IStringConverterFactory converterFactory) { - CONVERTER_FACTORIES.add(converterFactory); + CONVERTER_FACTORIES.addFirst(converterFactory); } public Class> findConverter(Class cls) { diff --git a/src/main/java/com/beust/jcommander/internal/Lists.java b/src/main/java/com/beust/jcommander/internal/Lists.java index 8666fe4..c4017c0 100644 --- a/src/main/java/com/beust/jcommander/internal/Lists.java +++ b/src/main/java/com/beust/jcommander/internal/Lists.java @@ -20,19 +20,30 @@ package com.beust.jcommander.internal; import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedList; import java.util.List; public class Lists { - public static List newArrayList() { - return new ArrayList(); - } - - public static List newArrayList(Collection c) { - return new ArrayList(c); - } - - public static List newArrayList(int size) { - return new ArrayList(size); - } + public static List newArrayList() { + return new ArrayList(); + } + + public static List newArrayList(Collection c) { + return new ArrayList(c); + } + + public static List newArrayList(int size) { + return new ArrayList(size); + } + + public static LinkedList newLinkedList() { + return new LinkedList(); + } + + public static LinkedList newLinkedList(Collection c) { + return new LinkedList(c); + } + + } -- cgit v1.2.3 From 4804ce09adb4fe1227850edc5ef4545528704678 Mon Sep 17 00:00:00 2001 From: rodionmoiseev Date: Sat, 28 May 2011 19:15:08 +0900 Subject: Added support for command aliases, e.g. "ci" for "commit" command, etc. Any number of aliases can be optionally specified to the addCommand() method. In usage output commands containing aliases will be formatted with a post-fixed comma-separated list of aliases in brackets, e.g. commit(ci,cmt). usage(String) series of methods also accept both commands and aliases. All existing API should be compatible with previous versions. --- src/main/java/com/beust/jcommander/JCommander.java | 184 +++++++++++++++++++-- 1 file changed, 167 insertions(+), 17 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 104f6ee..da3cd6c 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -36,9 +36,11 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.LinkedList; import java.util.Map; @@ -114,14 +116,24 @@ public class JCommander { /** * List of commands and their instance. */ - private Map m_commands = Maps.newLinkedHashMap(); + private Map m_commands = Maps.newLinkedHashMap(); + /** + * Alias database for reverse lookup + */ + private Map aliasMap = Maps.newLinkedHashMap(); /** * The name of the command after the parsing has run. */ private String m_parsedCommand; - private String m_programName; + /** + * The name of command or alias as it was passed to the + * command line + */ + private String m_parsedAlias; + + private ProgramName m_programName; /** * The factories used to look up string converters. @@ -582,9 +594,10 @@ public class JCommander { // // Command parsing // - JCommander jc = m_commands.get(arg); + JCommander jc = findCommandByAlias(arg); if (jc == null) throw new MissingCommandException("Expected a command, got " + arg); - m_parsedCommand = arg; + m_parsedCommand = jc.m_programName.name; + m_parsedAlias = arg; //preserve the original form // Found a valid command, ask it to parse the remainder of the arguments. // Setting the boolean commandParsed to true will force the current @@ -699,7 +712,17 @@ public class JCommander { * Set the program name (used only in the usage). */ public void setProgramName(String name) { - m_programName = name; + setProgramName(name, new String[0]); + } + + /** + * Set the program name + * + * @param name program name + * @param aliases aliases to the program name + */ + public void setProgramName(String name, String... aliases) { + m_programName = new ProgramName(name, Arrays.asList(aliases)); } /** @@ -716,7 +739,7 @@ public class JCommander { */ public void usage(String commandName, StringBuilder out) { String description = getCommandDescription(commandName); - JCommander jc = m_commands.get(commandName); + JCommander jc = findCommandByAlias(commandName); if (description != null) { out.append(description); out.append("\n"); @@ -728,7 +751,7 @@ public class JCommander { * @return the description of the command. */ public String getCommandDescription(String commandName) { - JCommander jc = m_commands.get(commandName); + JCommander jc = findCommandByAlias(commandName); if (jc == null) { throw new ParameterException("Asking description for unknown command: " + commandName); } @@ -754,12 +777,12 @@ public class JCommander { */ public void usage(StringBuilder out) { if (m_descriptions == null) createDescriptions(); - boolean hasCommands = ! m_commands.isEmpty(); + boolean hasCommands = !m_commands.isEmpty(); // // First line of the usage // - String programName = m_programName != null ? m_programName : "
"; + String programName = m_programName != null ? m_programName.getDisplayName() : "
"; out.append("Usage: " + programName + " [options]"); if (hasCommands) out.append(" [command] [command options]"); out.append("\n"); @@ -818,10 +841,11 @@ public class JCommander { // The magic value 3 is the number of spaces between the name of the option // and its description int ln = longestName(m_commands.keySet()) + 3; - for (Map.Entry commands : m_commands.entrySet()) { - String name = commands.getKey(); - int spaceCount = ln - name.length(); - out.append(" " + name + s(spaceCount) + getCommandDescription(name) + "\n"); + for (Map.Entry commands : m_commands.entrySet()) { + ProgramName progName = commands.getKey(); + String dispName = progName.getDisplayName(); + int spaceCount = ln - dispName.length(); + out.append(" " + dispName + s(spaceCount) + getCommandDescription(progName.name) + "\n"); } } } @@ -976,19 +1000,64 @@ public class JCommander { * Add a command object. */ public void addCommand(String name, Object object) { + addCommand(name, object, new String[0]); + } + + /** + * Add a command object. + */ + public void addCommand(String name, Object object, String... aliases) { JCommander jc = new JCommander(object); - jc.setProgramName(name); - m_commands.put(name, jc); + jc.setProgramName(name, aliases); + ProgramName progName = jc.m_programName; + m_commands.put(progName, jc); + + /* + * Register aliases + */ + //register command name as an alias of itself for reverse lookup + //Note: Name clash check is intentionally omitted to resemble the + // original behaviour of clashing commands. + // Aliases are, however, are strictly checked for name clashes. + aliasMap.put(name, progName); + for (String alias : aliases) { + //omit pointless aliases to avoid name clash exception + if (!alias.equals(name)) { + ProgramName mappedName = aliasMap.get(alias); + if (mappedName != null && !mappedName.equals(progName)) { + throw new ParameterException("Cannot set alias " + alias + + " for " + name + + " command because it has already been defined for " + + mappedName.name + " command"); + } + aliasMap.put(alias, progName); + } + } } public Map getCommands() { - return m_commands; + Map res = Maps.newLinkedHashMap(); + for (Map.Entry entry : m_commands.entrySet()) { + res.put(entry.getKey().name, entry.getValue()); + } + return res; } public String getParsedCommand() { return m_parsedCommand; } + /** + * The name of the command or the alias in the form it was + * passed to the command line. null if no + * command or alias was specified. + * + * @return Name of command or alias passed to command line. If none passed: null. + */ + public String getParsedAlias() { + return m_parsedAlias; + } + /** * @return n spaces */ @@ -1008,5 +1077,86 @@ public class JCommander { public List getObjects() { return m_objects; } -} + /* + * Reverse lookup JCommand object by command's name or its alias + */ + private JCommander findCommandByAlias(String commandOrAlias) { + ProgramName progName = aliasMap.get(commandOrAlias); + if (progName == null) { + return null; + } + JCommander jc = m_commands.get(progName); + if (jc == null) { + throw new IllegalStateException( + "There appears to be inconsistency in the internal command database. " + + " This is likely a bug. Please report."); + } + return jc; + } + + private static final class ProgramName { + private final String name; + private final List aliases; + + ProgramName(String name) { + this(name, Collections.emptyList()); + } + + ProgramName(String name, List aliases) { + this.name = name; + this.aliases = aliases; + } + + private String getDisplayName() { + StringBuilder sb = new StringBuilder(); + sb.append(name); + if (!aliases.isEmpty()) { + sb.append("("); + Iterator aliasesIt = aliases.iterator(); + while (aliasesIt.hasNext()) { + sb.append(aliasesIt.next()); + if (aliasesIt.hasNext()) { + sb.append(","); + } + } + sb.append(")"); + } + return sb.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ProgramName other = (ProgramName) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + /* + * Important: ProgramName#toString() is used by longestName(Collection) function + * to format usage output. + */ + @Override + public String toString() { + return getDisplayName(); + } + } +} -- cgit v1.2.3 From b9893ab2c4547b75942f73f96d20b37d1e245689 Mon Sep 17 00:00:00 2001 From: rodionmoiseev Date: Sun, 29 May 2011 11:37:46 +0900 Subject: Fixed issue #64 (wrong default value behaviour in for list parameters), and added support for Set parameters. Fix for #64: * ParameterDescription#m_assigned flag was being set too early, meaning it could become true even in case of an exception. To fix, moved it to the end of the try block. * Now we can use m_assigned, to test if the fields is being set for the first time, and use it to clear default values for collection parameters. Added support for Set type parameters, and provided a clearer exception for unsupported Collection type parameters (before the fix, a ClassCastException would be thrown). Additional support for Stack and Queue types could be added but would require a little more testing. Not sure of how useful Queues and Stacks would be anyway. --- .../com/beust/jcommander/ParameterDescription.java | 34 +++++++++++++++++++--- .../java/com/beust/jcommander/internal/Sets.java | 5 ++++ 2 files changed, 35 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 210d0ba..488a7b0 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -20,6 +20,7 @@ package com.beust.jcommander; import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Sets; import com.beust.jcommander.validators.NoValidator; import java.lang.reflect.Field; @@ -189,16 +190,15 @@ public class ParameterDescription { Class type = m_field.getType(); - if (! isDefault) m_assigned = true; Object convertedValue = m_jCommander.convertValue(this, value); boolean isCollection = Collection.class.isAssignableFrom(type); try { if (isCollection) { @SuppressWarnings("unchecked") - List l = (List) m_field.get(m_object); - if (l == null) { - l = Lists.newArrayList(); + Collection l = (Collection) m_field.get(m_object); + if (l == null || fieldIsSetForTheFirstTime(isDefault)) { + l = newCollection(type); m_field.set(m_object, l); } if (convertedValue instanceof Collection) { @@ -211,12 +211,38 @@ public class ParameterDescription { } else { m_field.set(m_object, convertedValue); } + if (! isDefault) m_assigned = true; } catch(IllegalAccessException ex) { ex.printStackTrace(); } } + /* + * Creates a new collection for the field's type. + * + * Currently only List and Set are supported. Support for + * Queues and Stacks could be useful. + */ + private Collection newCollection(Class type) { + if(List.class.isAssignableFrom(type)){ + return Lists.newArrayList(); + } else if(Set.class.isAssignableFrom(type)){ + return Sets.newLinkedHashSet(); + } else { + throw new ParameterException("Parameters of Collection type '" + type.getSimpleName() + + "' are not supported. Please use List or Set instead."); + } + } + + /* + * Tests if its the first time a non-default value is + * being added to the field. + */ + private boolean fieldIsSetForTheFirstTime(boolean isDefault) { + return (!isDefault && !m_assigned); + } + public boolean isNumber() { Class type = m_field.getType(); return type.equals(Integer.class) || type.equals(int.class) diff --git a/src/main/java/com/beust/jcommander/internal/Sets.java b/src/main/java/com/beust/jcommander/internal/Sets.java index 221376a..77949c3 100644 --- a/src/main/java/com/beust/jcommander/internal/Sets.java +++ b/src/main/java/com/beust/jcommander/internal/Sets.java @@ -19,6 +19,7 @@ package com.beust.jcommander.internal; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; public class Sets { @@ -27,4 +28,8 @@ public class Sets { return new HashSet(); } + public static Set newLinkedHashSet() { + return new LinkedHashSet(); + } + } -- cgit v1.2.3 From 307ad87e19e6c8ae91d7dec7acfe308873097e26 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 31 May 2011 11:31:33 -0700 Subject: Minor fixes on top of rodionmoiseev's patch. - Javadoc update - Disabled a test. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index da3cd6c..62d2cd9 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1004,7 +1004,7 @@ public class JCommander { } /** - * Add a command object. + * Add a command object and its aliases. */ public void addCommand(String name, Object object, String... aliases) { JCommander jc = new JCommander(object); -- cgit v1.2.3 From fe8a696f6c65438505eb26d8b734d34910932ef7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 13 Jun 2011 13:35:31 -0700 Subject: Fixed: Default values with a validator were being validate at parse() time instead of creation time. --- .../com/beust/jcommander/ParameterDescription.java | 35 +++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 488a7b0..7b43677 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -104,6 +104,15 @@ public class ParameterDescription { m_default = m_field.get(m_object); } catch (Exception e) { } + + // + // Validate default values, if any and if applicable + // + if (m_default != null) { + String[] names = m_parameterAnnotation.names(); + String name = names.length > 0 ? names[0] : ""; + validateParameter(name, m_default.toString()); + } } public String getLongestName() { @@ -176,17 +185,7 @@ public class ParameterDescription { + " once."); } - Class validator = m_parameterAnnotation.validateWith(); - if (validator != NoValidator.class) { - try { - p("Validating parameter:" + name + " value:" + value + " validator:" + validator); - validator.newInstance().validate(name, value); - } catch (InstantiationException e) { - throw new ParameterException("Can't instantiate validator:" + e); - } catch (IllegalAccessException e) { - throw new ParameterException("Can't instantiate validator:" + e); - } - } + validateParameter(name, value); Class type = m_field.getType(); @@ -218,6 +217,20 @@ public class ParameterDescription { } } + private void validateParameter(String name, String value) { + Class validator = m_parameterAnnotation.validateWith(); + if (validator != NoValidator.class) { + try { + p("Validating parameter:" + name + " value:" + value + " validator:" + validator); + validator.newInstance().validate(name, value); + } catch (InstantiationException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } catch (IllegalAccessException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } + } + } + /* * Creates a new collection for the field's type. * -- cgit v1.2.3 From c199c87fcd7d702047dd813fbc4224c7d85fd95d Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 7 Jul 2011 13:34:54 -0700 Subject: Added: usage() now displays the options for each command as well --- src/main/java/com/beust/jcommander/JCommander.java | 75 +++++++++++++--------- 1 file changed, 45 insertions(+), 30 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 62d2cd9..260942f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -596,7 +596,7 @@ public class JCommander { // JCommander jc = findCommandByAlias(arg); if (jc == null) throw new MissingCommandException("Expected a command, got " + arg); - m_parsedCommand = jc.m_programName.name; + m_parsedCommand = jc.m_programName.m_name; m_parsedAlias = arg; //preserve the original form // Found a valid command, ask it to parse the remainder of the arguments. @@ -738,13 +738,21 @@ public class JCommander { * Store the help for the command in the passed string builder. */ public void usage(String commandName, StringBuilder out) { + usage(commandName, out, ""); + } + + /** + * Store the help for the command in the passed string builder, indenting + * every line with "indent". + */ + public void usage(String commandName, StringBuilder out, String indent) { String description = getCommandDescription(commandName); JCommander jc = findCommandByAlias(commandName); if (description != null) { - out.append(description); + out.append(indent).append(description); out.append("\n"); } - jc.usage(out); + jc.usage(out, indent); } /** @@ -776,6 +784,10 @@ public class JCommander { * Store the help in the passed string builder. */ public void usage(StringBuilder out) { + usage(out, ""); + } + + public void usage(StringBuilder out, String indent) { if (m_descriptions == null) createDescriptions(); boolean hasCommands = !m_commands.isEmpty(); @@ -783,9 +795,9 @@ public class JCommander { // First line of the usage // String programName = m_programName != null ? m_programName.getDisplayName() : "
"; - out.append("Usage: " + programName + " [options]"); - if (hasCommands) out.append(" [command] [command options]"); - out.append("\n"); + out.append(indent).append("Usage: " + programName + " [options]"); + if (hasCommands) out.append(indent).append(" [command] [command options]"); +// out.append("\n"); if (m_mainParameterAnnotation != null) { out.append(" " + m_mainParameterAnnotation.description() + "\n"); } @@ -818,18 +830,19 @@ public class JCommander { // // Display all the names and descriptions // - if (sorted.size() > 0) out.append(" Options:\n"); + if (sorted.size() > 0) out.append(indent).append(" Options:\n"); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; int start = out.length(); - out.append(" " + out.append(indent).append(" " + (pd.getParameter().required() ? "* " : " ") + pd.getNames() + s(spaceCount)); - int indent = out.length() - start; - wrapDescription(out, indent, pd.getDescription()); + int indentCount = out.length() - start; + wrapDescription(out, indentCount, pd.getDescription()); Object def = pd.getDefault(); - if (def != null) out.append("\n" + spaces(indent + 1)).append("Default: " + def); + if (def != null) out.append("\n" + spaces(indentCount + 1)) + .append("Default: " + def); out.append("\n"); } @@ -840,12 +853,14 @@ public class JCommander { out.append(" Commands:\n"); // The magic value 3 is the number of spaces between the name of the option // and its description - int ln = longestName(m_commands.keySet()) + 3; for (Map.Entry commands : m_commands.entrySet()) { ProgramName progName = commands.getKey(); String dispName = progName.getDisplayName(); - int spaceCount = ln - dispName.length(); - out.append(" " + dispName + s(spaceCount) + getCommandDescription(progName.name) + "\n"); + out.append(indent).append(" " + dispName); // + s(spaceCount) + getCommandDescription(progName.name) + "\n"); + + // Options for this command + usage(progName.getName(), out, " "); + out.append("\n"); } } } @@ -1028,7 +1043,7 @@ public class JCommander { throw new ParameterException("Cannot set alias " + alias + " for " + name + " command because it has already been defined for " - + mappedName.name + " command"); + + mappedName.m_name + " command"); } aliasMap.put(alias, progName); } @@ -1038,7 +1053,7 @@ public class JCommander { public Map getCommands() { Map res = Maps.newLinkedHashMap(); for (Map.Entry entry : m_commands.entrySet()) { - res.put(entry.getKey().name, entry.getValue()); + res.put(entry.getKey().m_name, entry.getValue()); } return res; } @@ -1096,24 +1111,24 @@ public class JCommander { } private static final class ProgramName { - private final String name; - private final List aliases; + private final String m_name; + private final List m_aliases; - ProgramName(String name) { - this(name, Collections.emptyList()); + ProgramName(String name, List aliases) { + m_name = name; + m_aliases = aliases; } - ProgramName(String name, List aliases) { - this.name = name; - this.aliases = aliases; + public String getName() { + return m_name; } private String getDisplayName() { StringBuilder sb = new StringBuilder(); - sb.append(name); - if (!aliases.isEmpty()) { + sb.append(m_name); + if (!m_aliases.isEmpty()) { sb.append("("); - Iterator aliasesIt = aliases.iterator(); + Iterator aliasesIt = m_aliases.iterator(); while (aliasesIt.hasNext()) { sb.append(aliasesIt.next()); if (aliasesIt.hasNext()) { @@ -1129,7 +1144,7 @@ public class JCommander { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); return result; } @@ -1142,10 +1157,10 @@ public class JCommander { if (getClass() != obj.getClass()) return false; ProgramName other = (ProgramName) obj; - if (name == null) { - if (other.name != null) + if (m_name == null) { + if (other.m_name != null) return false; - } else if (!name.equals(other.name)) + } else if (!m_name.equals(other.m_name)) return false; return true; } -- cgit v1.2.3 From 4f4ea1fb335b79e05f1b24e217d796fdb3e077de Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 14 Jul 2011 11:17:16 -0700 Subject: Fixed: GITHUB-73: descriptionKey was being ignored on main parameters --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 260942f..cd5325e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -798,8 +798,8 @@ public class JCommander { out.append(indent).append("Usage: " + programName + " [options]"); if (hasCommands) out.append(indent).append(" [command] [command options]"); // out.append("\n"); - if (m_mainParameterAnnotation != null) { - out.append(" " + m_mainParameterAnnotation.description() + "\n"); + if (m_mainParameterDescription != null) { + out.append(" " + m_mainParameterDescription.getDescription() + "\n"); } // -- cgit v1.2.3 From 8a3f5625ab132ff8f5d62650cc58455628e51038 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 15 Jul 2011 10:55:52 -0700 Subject: Added: commandDescriptionKey to @Parameters, to allow internationalized command descriptions --- src/main/java/com/beust/jcommander/JCommander.java | 11 ++++++++++- src/main/java/com/beust/jcommander/Parameters.java | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index cd5325e..3308880 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -766,11 +766,20 @@ public class JCommander { Parameters p = jc.getObjects().get(0).getClass().getAnnotation(Parameters.class); String result = jc.getMainParameterDescription(); - if (p != null) result = p.commandDescription(); + if (p != null) result = getI18nString(p.commandDescriptionKey(), p.commandDescription()); return result; } + /** + * @return The internationalized version of the string if available, otherwise + * return def. + */ + private String getI18nString(String key, String def) { + String s = m_bundle != null ? m_bundle.getString(key) : null; + return s != null ? s : def; + } + /** * Display a the help on System.out. */ diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index cffc030..e25d1f2 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -55,4 +55,9 @@ public @interface Parameters { * description when @{link JCommander#usage} is invoked. */ String commandDescription() default ""; + + /** + * @return the key used to find the command description in the resource bundle. + */ + String commandDescriptionKey() default ""; } -- cgit v1.2.3 From 2ee07bc8765f4873b69423e6185120d176c49a2b Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 27 Jul 2011 10:32:36 -0700 Subject: Fixed: "-args=a=b,b=c" was not being parsed correctly (Michael Lancaster) --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3308880..af191d7 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -320,7 +320,7 @@ public class JCommander { if (isOption(v1, arg)) { String sep = getSeparatorFor(v1, arg); if (! " ".equals(sep)) { - String[] sp = arg.split("[" + sep + "]"); + String[] sp = arg.split("[" + sep + "]", 2); for (String ssp : sp) { vResult2.add(ssp); } -- cgit v1.2.3 From 54b130ae8ae6a1c455a3290bfd53d26698dc72a6 Mon Sep 17 00:00:00 2001 From: Stevo Slavic Date: Mon, 1 Aug 2011 18:35:18 +0200 Subject: [fix:]Fixes initializing default values --- src/main/java/com/beust/jcommander/JCommander.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index af191d7..c9c1823 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -261,6 +261,10 @@ public class JCommander { for (ParameterDescription pd : m_descriptions.values()) { initializeDefaultValue(pd); } + + for (Map.Entry entry : m_commands.entrySet()) { + entry.getValue().initializeDefaultValues(); + } } } @@ -925,6 +929,10 @@ public class JCommander { */ public void setDefaultProvider(IDefaultProvider defaultProvider) { m_defaultProvider = defaultProvider; + + for (Map.Entry entry : m_commands.entrySet()) { + entry.getValue().setDefaultProvider(defaultProvider); + } } public void addConverterFactory(IStringConverterFactory converterFactory) { @@ -1033,6 +1041,7 @@ public class JCommander { public void addCommand(String name, Object object, String... aliases) { JCommander jc = new JCommander(object); jc.setProgramName(name, aliases); + jc.setDefaultProvider(m_defaultProvider); ProgramName progName = jc.m_programName; m_commands.put(progName, jc); -- cgit v1.2.3 From 876c9776ebe75ca46504847a4807b681ef5d5e4f Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 17 Aug 2011 11:09:57 -0700 Subject: Fixed: Fields of type Set (HashSet and SortedSet) are now supported --- .../java/com/beust/jcommander/ParameterDescription.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 7b43677..b52c695 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -19,16 +19,18 @@ package com.beust.jcommander; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Sets; import com.beust.jcommander.validators.NoValidator; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; public class ParameterDescription { private Object m_object; @@ -237,12 +239,12 @@ public class ParameterDescription { * Currently only List and Set are supported. Support for * Queues and Stacks could be useful. */ + @SuppressWarnings("unchecked") private Collection newCollection(Class type) { - if(List.class.isAssignableFrom(type)){ - return Lists.newArrayList(); - } else if(Set.class.isAssignableFrom(type)){ - return Sets.newLinkedHashSet(); - } else { + if (SortedSet.class.isAssignableFrom(type)) return new TreeSet(); + else if (LinkedHashSet.class.isAssignableFrom(type)) return new LinkedHashSet(); + else if (List.class.isAssignableFrom(type)) return new ArrayList(); + else { throw new ParameterException("Parameters of Collection type '" + type.getSimpleName() + "' are not supported. Please use List or Set instead."); } -- cgit v1.2.3 From 8ce1ca7ee017b4ab886879cc4c0dd878fdbff2f9 Mon Sep 17 00:00:00 2001 From: Alex Cornejo Date: Tue, 30 Aug 2011 16:42:26 -0400 Subject: Added support for floats and doubles. These types are essential for almost any scientific application, I was shocked to find they were not already supported. --- .../com/beust/jcommander/ParameterDescription.java | 10 +++++- .../jcommander/converters/DoubleConverter.java | 42 ++++++++++++++++++++++ .../jcommander/converters/FloatConverter.java | 42 ++++++++++++++++++++++ .../internal/DefaultConverterFactory.java | 8 ++++- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/converters/DoubleConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/FloatConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index b52c695..e8ac3d5 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -261,7 +261,15 @@ public class ParameterDescription { public boolean isNumber() { Class type = m_field.getType(); return type.equals(Integer.class) || type.equals(int.class) - || type.equals(Long.class) || type.equals(long.class); + || type.equals(Long.class) || type.equals(long.class) + || type.equals(Float.class) || type.equals(float.class) + || type.equals(Double.class) || type.equals(double.class); + } + + public boolean isFractional() { + Class type = m_field.getType(); + return type.equals(Float.class) || type.equals(float.class) + || type.equals(Double.class) || type.equals(double.class); } private void p(String string) { diff --git a/src/main/java/com/beust/jcommander/converters/DoubleConverter.java b/src/main/java/com/beust/jcommander/converters/DoubleConverter.java new file mode 100644 index 0000000..0c36c68 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/DoubleConverter.java @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; + +/** + * Convert a string to a double. + * + * @author acornejo + */ +public class DoubleConverter extends BaseConverter { + + public DoubleConverter(String optionName) { + super(optionName); + } + + public Double convert(String value) { + try { + return Double.parseDouble(value); + } catch(NumberFormatException ex) { + throw new ParameterException(getErrorString(value, "a double")); + } + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/FloatConverter.java b/src/main/java/com/beust/jcommander/converters/FloatConverter.java new file mode 100644 index 0000000..2e2eff8 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/FloatConverter.java @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; + +/** + * Convert a string to a float. + * + * @author acornejo + */ +public class FloatConverter extends BaseConverter { + + public FloatConverter(String optionName) { + super(optionName); + } + + public Float convert(String value) { + try { + return Float.parseFloat(value); + } catch(NumberFormatException ex) { + throw new ParameterException(getErrorString(value, "a float")); + } + } + +} diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index bbe0cd1..26ab0fc 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -24,6 +24,8 @@ import com.beust.jcommander.converters.BooleanConverter; import com.beust.jcommander.converters.FileConverter; import com.beust.jcommander.converters.IntegerConverter; import com.beust.jcommander.converters.LongConverter; +import com.beust.jcommander.converters.FloatConverter; +import com.beust.jcommander.converters.DoubleConverter; import com.beust.jcommander.converters.StringConverter; import java.io.File; @@ -34,7 +36,7 @@ public class DefaultConverterFactory implements IStringConverterFactory { * A map of converters per class. */ private static Map>> m_classConverters; - + static { m_classConverters = Maps.newHashMap(); m_classConverters.put(String.class, StringConverter.class); @@ -42,6 +44,10 @@ public class DefaultConverterFactory implements IStringConverterFactory { m_classConverters.put(int.class, IntegerConverter.class); m_classConverters.put(Long.class, LongConverter.class); m_classConverters.put(long.class, LongConverter.class); + m_classConverters.put(Float.class, FloatConverter.class); + m_classConverters.put(float.class, FloatConverter.class); + m_classConverters.put(Double.class, DoubleConverter.class); + m_classConverters.put(double.class, DoubleConverter.class); m_classConverters.put(Boolean.class, BooleanConverter.class); m_classConverters.put(boolean.class, BooleanConverter.class); m_classConverters.put(File.class, FileConverter.class); -- cgit v1.2.3 From ee74c7bf2ea0f7b17093650fdd78b0f8ffa343b9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 2 Sep 2011 10:13:11 -0700 Subject: Fixed silly setter mistake. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index b52c695..0137f43 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -19,8 +19,6 @@ package com.beust.jcommander; -import com.beust.jcommander.validators.NoValidator; - import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; @@ -32,6 +30,8 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import com.beust.jcommander.validators.NoValidator; + public class ParameterDescription { private Object m_object; private Parameter m_parameterAnnotation; @@ -170,7 +170,7 @@ public class ParameterDescription { public void setAssigned(boolean b) { - m_assigned = true; + m_assigned = b; } /** -- cgit v1.2.3 From d9edcaec709764312eea63f825308e2ae4ddaddd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 2 Sep 2011 10:44:53 -0700 Subject: Minor collection fixes. --- .../java/com/beust/jcommander/ParameterDescription.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 47e3cd7..5b674ca 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -22,6 +22,7 @@ package com.beust.jcommander; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -243,6 +244,7 @@ public class ParameterDescription { private Collection newCollection(Class type) { if (SortedSet.class.isAssignableFrom(type)) return new TreeSet(); else if (LinkedHashSet.class.isAssignableFrom(type)) return new LinkedHashSet(); + else if (Set.class.isAssignableFrom(type)) return new HashSet(); else if (List.class.isAssignableFrom(type)) return new ArrayList(); else { throw new ParameterException("Parameters of Collection type '" + type.getSimpleName() @@ -258,20 +260,6 @@ public class ParameterDescription { return (!isDefault && !m_assigned); } - public boolean isNumber() { - Class type = m_field.getType(); - return type.equals(Integer.class) || type.equals(int.class) - || type.equals(Long.class) || type.equals(long.class) - || type.equals(Float.class) || type.equals(float.class) - || type.equals(Double.class) || type.equals(double.class); - } - - public boolean isFractional() { - Class type = m_field.getType(); - return type.equals(Float.class) || type.equals(float.class) - || type.equals(Double.class) || type.equals(double.class); - } - private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[ParameterDescription] " + string); -- cgit v1.2.3 From d2a567ff013254ee00b600d0eb298770d35b089f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Beust?= Date: Mon, 3 Oct 2011 06:04:41 -0700 Subject: Issue 80: missing new line when no main parameter is present. --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c9c1823..0ae4e85 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -41,8 +41,8 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.ResourceBundle; @@ -812,7 +812,7 @@ public class JCommander { if (hasCommands) out.append(indent).append(" [command] [command options]"); // out.append("\n"); if (m_mainParameterDescription != null) { - out.append(" " + m_mainParameterDescription.getDescription() + "\n"); + out.append(" " + m_mainParameterDescription.getDescription()); } // @@ -843,7 +843,7 @@ public class JCommander { // // Display all the names and descriptions // - if (sorted.size() > 0) out.append(indent).append(" Options:\n"); + if (sorted.size() > 0) out.append(indent).append("\n Options:\n"); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; -- cgit v1.2.3 From c709e6db81d11fe4aa6c573775ba5577902aa35c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Beust?= Date: Mon, 3 Oct 2011 06:53:22 -0700 Subject: Implemented variable arities. --- .../java/com/beust/jcommander/IVariableArity.java | 16 ++++ src/main/java/com/beust/jcommander/JCommander.java | 103 ++++++++++++++------- src/main/java/com/beust/jcommander/Parameter.java | 5 + 3 files changed, 89 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IVariableArity.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IVariableArity.java b/src/main/java/com/beust/jcommander/IVariableArity.java new file mode 100644 index 0000000..e7499c9 --- /dev/null +++ b/src/main/java/com/beust/jcommander/IVariableArity.java @@ -0,0 +1,16 @@ +package com.beust.jcommander; + +/** + * Must be implemented by argument classes that contain at least one + * @Parameter with "variableArity = true". + */ +public interface IVariableArity { + + /** + * @param optionName the name of the option to process. + * @param options the entire list of options. + * + * @return how many options were processed. + */ + int processVariableArity(String optionName, String[] options); +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0ae4e85..5735814 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -526,48 +526,28 @@ public class JCommander { char[] password = readPassword(pd.getDescription()); pd.addValue(new String(password)); } else { - // - // Regular option - // - Class fieldType = pd.getField().getType(); - - // Boolean, set to true as soon as we see it, unless it specified - // an arity of 1, in which case we need to read the next value - if ((fieldType == boolean.class || fieldType == Boolean.class) - && pd.getParameter().arity() == -1) { - pd.addValue("true"); - m_requiredFields.remove(pd.getField()); + if (pd.getParameter().variableArity()) { + // + // Variable arity? + // + i = processVariableArity(args, i, pd); } else { - // Regular parameter, use the arity to tell use how many values - // we need to consume - int arity = pd.getParameter().arity(); - int n = (arity != -1 ? arity : 1); - - // Special case for boolean parameters of arity 0 - if (n == 0 && - (Boolean.class.isAssignableFrom(fieldType) - || boolean.class.isAssignableFrom(fieldType))) { + // + // Regular option + // + Class fieldType = pd.getField().getType(); + + // Boolean, set to true as soon as we see it, unless it specified + // an arity of 1, in which case we need to read the next value + if ((fieldType == boolean.class || fieldType == Boolean.class) + && pd.getParameter().arity() == -1) { pd.addValue("true"); m_requiredFields.remove(pd.getField()); - } else if (i < args.length - 1) { - int offset = "--".equals(args[i + 1]) ? 1 : 0; - - if (i + n < args.length) { - for (int j = 1; j <= n; j++) { - pd.addValue(trim(args[i + j + offset])); - m_requiredFields.remove(pd.getField()); - } - i += n + offset; - } else { - throw new ParameterException("Expected " + n + " values after " + arg); - } } else { - throw new ParameterException("Expected a value after parameter " + arg); + i = processFixedArity(args, i, pd, fieldType); } } } - } else { - throw new ParameterException("Unknown option: " + a); } } else { @@ -623,6 +603,59 @@ public class JCommander { } + /** + * @return the number of options that were processed. + */ + private int processVariableArity(String[] args, int index, ParameterDescription pd) { + Object arg = pd.getObject(); + if (! (arg instanceof IVariableArity)) { + throw new ParameterException("Arg class " + arg.getClass() + + " should implement IVariableArity"); + } + + IVariableArity va = (IVariableArity) arg; + List currentArgs = Lists.newArrayList(); + for (int j = index + 1; j < args.length; j++) { + currentArgs.add(args[j]); + } + int result = va.processVariableArity(pd.getParameter().names()[0], + currentArgs.toArray(new String[0])); + return result; + } + + private int processFixedArity(String[] args, int index, ParameterDescription pd, + Class fieldType) { + // Regular parameter, use the arity to tell use how many values + // we need to consume + String arg = args[index]; + int arity = pd.getParameter().arity(); + int n = (arity != -1 ? arity : 1); + + // Special case for boolean parameters of arity 0 + if (n == 0 && + (Boolean.class.isAssignableFrom(fieldType) + || boolean.class.isAssignableFrom(fieldType))) { + pd.addValue("true"); + m_requiredFields.remove(pd.getField()); + } else if (index < args.length - 1) { + int offset = "--".equals(args[index + 1]) ? 1 : 0; + + if (index + n < args.length) { + for (int j = 1; j <= n; j++) { + pd.addValue(trim(args[index + j + offset])); + m_requiredFields.remove(pd.getField()); + } + index += n + offset; + } else { + throw new ParameterException("Expected " + n + " values after " + arg); + } + } else { + throw new ParameterException("Expected a value after parameter " + arg); + } + + return index; + } + /** * Invoke Console.readPassword through reflection to avoid depending * on Java 6. diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 7003f5d..c697d2e 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -78,4 +78,9 @@ public @interface Parameter { * The validation class to use. */ Class validateWith() default NoValidator.class; + + /** + * @return true if this parameter has a variable arity. See @{IVariableArity} + */ + boolean variableArity() default false; } -- cgit v1.2.3 From cbdb7070bd2101febc1b08b8cb5d26c54e150a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Beust?= Date: Wed, 5 Oct 2011 23:14:20 -0700 Subject: Added: JCommander#setParameterDescriptionComparator for better control over usage(). --- src/main/java/com/beust/jcommander/JCommander.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 5735814..b9a93fa 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -135,6 +135,13 @@ public class JCommander { private ProgramName m_programName; + private Comparator m_parameterDescriptionComparator + = new Comparator() { + public int compare(ParameterDescription p0, ParameterDescription p1) { + return p0.getLongestName().compareTo(p1.getLongestName()); + } + }; + /** * The factories used to look up string converters. */ @@ -867,11 +874,7 @@ public class JCommander { // // Sort the options // - Collections.sort(sorted, new Comparator() { - public int compare(ParameterDescription p0, ParameterDescription p1) { - return p0.getLongestName().compareTo(p1.getLongestName()); - } - }); + Collections.sort(sorted, getParameterDescriptionComparator()); // // Display all the names and descriptions @@ -911,6 +914,14 @@ public class JCommander { } } + private Comparator getParameterDescriptionComparator() { + return m_parameterDescriptionComparator; + } + + public void setParameterDescriptionComparator(Comparator c) { + m_parameterDescriptionComparator = c; + } + private void wrapDescription(StringBuilder out, int indent, String description) { int max = 79; String[] words = description.split(" "); -- cgit v1.2.3 From 886538c8c4ae9df170c91706634b648916c7f84d Mon Sep 17 00:00:00 2001 From: Adrian Muraru Date: Thu, 20 Oct 2011 04:53:43 +0300 Subject: Added support for parameters defined as enum types --- src/main/java/com/beust/jcommander/JCommander.java | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b9a93fa..d374a6f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -40,6 +40,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -543,7 +544,7 @@ public class JCommander { // Regular option // Class fieldType = pd.getField().getType(); - + // Boolean, set to true as soon as we see it, unless it specified // an arity of 1, in which case we need to read the next value if ((fieldType == boolean.class || fieldType == Boolean.class) @@ -1008,8 +1009,14 @@ public class JCommander { // // Try to find a converter on the annotation // - if (converterClass == null || converterClass == NoConverter.class) { - converterClass = findConverter(type); + if ( converterClass == null || converterClass == NoConverter.class) { + // If no converter specified and type is enum, used enum values to convert + if (type.isEnum()){ + converterClass = type; + } else { + converterClass = findConverter(type); + } + } if (converterClass == null) { converterClass = StringConverter.class; @@ -1035,8 +1042,17 @@ public class JCommander { try { String[] names = annotation.names(); String optionName = names.length > 0 ? names[0] : "[Main class]"; - converter = instantiateConverter(optionName, converterClass); - result = converter.convert(value); + if (converterClass.isEnum()) { + try { + result = Enum.valueOf((Class) converterClass, value.toUpperCase()); + } catch (Exception e) { + throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" + + EnumSet.allOf((Class) converterClass)); + } + } else { + converter = instantiateConverter(optionName, converterClass); + result = converter.convert(value); + } } catch (InstantiationException e) { throw new ParameterException(e); } catch (IllegalAccessException e) { -- cgit v1.2.3 From 041bdac9067d4ce9c936ff1c0ae3856f2e240f15 Mon Sep 17 00:00:00 2001 From: Angus Date: Wed, 26 Oct 2011 00:22:53 +0100 Subject: Added support for BigDecimal arguments and related test. --- .../jcommander/converters/BigDecimalConverter.java | 43 ++++++++++++++++++++++ .../internal/DefaultConverterFactory.java | 3 ++ 2 files changed, 46 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java new file mode 100644 index 0000000..cd256a4 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; +import java.math.BigDecimal; + +/** + * Converts a String to a BigDecimal. + * + * @author angus + */ +public class BigDecimalConverter extends BaseConverter { + + public BigDecimalConverter(String optionName) { + super(optionName); + } + + @Override + public BigDecimal convert(String value) { + try { + return new BigDecimal(value); + } catch (NumberFormatException nfe) { + throw new ParameterException(getErrorString(value, "a BigDecimal")); + } + } +} diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index 26ab0fc..e622722 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -27,8 +27,10 @@ import com.beust.jcommander.converters.LongConverter; import com.beust.jcommander.converters.FloatConverter; import com.beust.jcommander.converters.DoubleConverter; import com.beust.jcommander.converters.StringConverter; +import com.beust.jcommander.converters.BigDecimalConverter; import java.io.File; +import java.math.BigDecimal; import java.util.Map; public class DefaultConverterFactory implements IStringConverterFactory { @@ -51,6 +53,7 @@ public class DefaultConverterFactory implements IStringConverterFactory { m_classConverters.put(Boolean.class, BooleanConverter.class); m_classConverters.put(boolean.class, BooleanConverter.class); m_classConverters.put(File.class, FileConverter.class); + m_classConverters.put(BigDecimal.class, BigDecimalConverter.class); } public Class> getConverter(Class forType) { -- cgit v1.2.3 From f923ee57617c8690d293909c53a4e109a8c2ba26 Mon Sep 17 00:00:00 2001 From: Angus Date: Wed, 26 Oct 2011 00:56:51 +0100 Subject: Added support for ISO 8601 Date arguments and related test. We currently only support the format yyyy-MM-dd (as it is all I need right now). In future this should be modified to support all ISO 8601 formats such as yyyy-MM-dd'T'HH:mm:ssZ. --- .../converters/ISO8601DateConverter.java | 49 ++++++++++++++++++++++ .../internal/DefaultConverterFactory.java | 3 ++ 2 files changed, 52 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java new file mode 100644 index 0000000..303f410 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; +import com.beust.jcommander.converters.BaseConverter; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Converts a String to a Date. + * TODO Modify to work with all valid ISO 8601 date formats (currently only works with yyyy-MM-dd). + * + * @author angus + */ +public class ISO8601DateConverter extends BaseConverter { + + private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + public ISO8601DateConverter(String optionName) { + super(optionName); + } + + @Override + public Date convert(String value) { + try { + return DATE_FORMAT.parse(value); + } catch (ParseException pe) { + throw new ParameterException(getErrorString(value, String.format("an ISO-8601 formatted date (%s)", DATE_FORMAT.toPattern()))); + } + } +} diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index e622722..fed5783 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -28,9 +28,11 @@ import com.beust.jcommander.converters.FloatConverter; import com.beust.jcommander.converters.DoubleConverter; import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.converters.BigDecimalConverter; +import com.beust.jcommander.converters.ISO8601DateConverter; import java.io.File; import java.math.BigDecimal; +import java.util.Date; import java.util.Map; public class DefaultConverterFactory implements IStringConverterFactory { @@ -54,6 +56,7 @@ public class DefaultConverterFactory implements IStringConverterFactory { m_classConverters.put(boolean.class, BooleanConverter.class); m_classConverters.put(File.class, FileConverter.class); m_classConverters.put(BigDecimal.class, BigDecimalConverter.class); + m_classConverters.put(Date.class, ISO8601DateConverter.class); } public Class> getConverter(Class forType) { -- cgit v1.2.3 From b02a7c5b3388b64a133847d3630450f099e6e141 Mon Sep 17 00:00:00 2001 From: Angus Date: Wed, 26 Oct 2011 01:34:50 +0100 Subject: Changed @author tag to "Angus Smithson" for my additions. --- src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java | 2 +- src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java index cd256a4..aa8a819 100644 --- a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java @@ -24,7 +24,7 @@ import java.math.BigDecimal; /** * Converts a String to a BigDecimal. * - * @author angus + * @author Angus Smithson */ public class BigDecimalConverter extends BaseConverter { diff --git a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java index 303f410..7429e0f 100644 --- a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java +++ b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java @@ -28,7 +28,7 @@ import java.util.Date; * Converts a String to a Date. * TODO Modify to work with all valid ISO 8601 date formats (currently only works with yyyy-MM-dd). * - * @author angus + * @author Angus Smithson */ public class ISO8601DateConverter extends BaseConverter { -- cgit v1.2.3 From 7021eade4657caf7ae25b19539bdc135619d248c Mon Sep 17 00:00:00 2001 From: Angus Date: Wed, 26 Oct 2011 01:37:42 +0100 Subject: Added CommaSeparatedBaseConverter, some subclasses and tests. Created CommaSeparatedBaseConverter which will make it quicker/easier to parse lists of a particular type into ArrayList. Added CommanSeparatedIntConverter and CommaSeparatedBigDecimalConverter, moved the old CommaSeparatedConverter to CommaSeparatedStringConverter. --- .../converters/CommaSeparatedBaseConverter.java | 51 ++++++++++++++++++++++ .../CommaSeparatedBigDecimalConverter.java | 38 ++++++++++++++++ .../converters/CommaSeparatedConverter.java | 37 ---------------- .../converters/CommaSeparatedIntConverter.java | 36 +++++++++++++++ .../converters/CommaSeparatedStringConverter.java | 36 +++++++++++++++ 5 files changed, 161 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java delete mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java create mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java new file mode 100644 index 0000000..454bca6 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; +import java.util.ArrayList; +import java.util.List; + +/** + * Base class for comma-separated converters which stores the name of the option and object type in case of errors. + * + * @author Angus Smithson + */ +abstract class CommaSeparatedBaseConverter extends BaseConverter> { + + private String m_typeDescription; + + public CommaSeparatedBaseConverter(String optionName, String typeDescription) { + super(optionName); + m_typeDescription = typeDescription; + } + + public List convert(String value) { + ArrayList al = new ArrayList(); + final String[] values = value.split(","); + try { + for (String s : values) al.add(getIndividualValue(s)); + } catch (Throwable t) { + throw new ParameterException(getErrorString(value, String.format("a list of type %s.", m_typeDescription))); + } + return al; + } + + abstract T getIndividualValue(String value); +} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java new file mode 100644 index 0000000..dae58c2 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import java.math.BigDecimal; + +/** + * Convert a string of comma separated numbers into a list of type BigDecimal. + * + * @author Angus Smithson + */ +public class CommaSeparatedBigDecimalConverter extends CommaSeparatedBaseConverter { + + public CommaSeparatedBigDecimalConverter(String optionName) { + super(optionName, "BigDecimal"); + } + + @Override + BigDecimal getIndividualValue(String value) { + return new BigDecimal(value); + } +} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java deleted file mode 100644 index b719bd4..0000000 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedConverter.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.beust.jcommander.converters; - -import com.beust.jcommander.IStringConverter; - -import java.util.Arrays; -import java.util.List; - -/** - * Convert a string of comma separated words into a list of string. - * - * @author cbeust - */ -public class CommaSeparatedConverter implements IStringConverter> { - - public List convert(String value) { - return Arrays.asList(value.split(",")); - } - -} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java new file mode 100644 index 0000000..dc98ecc --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +/** + * Convert a string of comma separated numbers into a list of type Integer. + * + * @author Angus Smithson + */ +public class CommaSeparatedIntConverter extends CommaSeparatedBaseConverter { + + public CommaSeparatedIntConverter(String optionName) { + super(optionName, "Integer"); + } + + @Override + Integer getIndividualValue(String value) { + return Integer.parseInt(value); + } +} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java new file mode 100644 index 0000000..a5cddf7 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +/** + * Convert a string of comma separated words into a list of type String. + * + * @author Angus Smithson + */ +public class CommaSeparatedStringConverter extends CommaSeparatedBaseConverter { + + public CommaSeparatedStringConverter(String optionName) { + super(optionName, "String"); + } + + @Override + String getIndividualValue(String value) { + return value; + } +} -- cgit v1.2.3 From b04b599b25214e01db50b3545160426b7500d895 Mon Sep 17 00:00:00 2001 From: rodionmoiseev Date: Sat, 5 Nov 2011 20:20:53 +0900 Subject: Support for delegated (mixin) parameters (issue #84) Added a new @ParametersDelegate annotation to tell JCommander parser to process all parametrised fields inside the annotated object. Any number of delegated parameters and any amount of nesting is allowed. fixes #84 --- src/main/java/com/beust/jcommander/JCommander.java | 10 +++++ .../com/beust/jcommander/ParametersDelegate.java | 44 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/ParametersDelegate.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d374a6f..b9fdb11 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -465,6 +465,7 @@ public class JCommander { p("Field:" + cls.getSimpleName() + "." + f.getName()); f.setAccessible(true); Annotation annotation = f.getAnnotation(Parameter.class); + Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class); if (annotation != null) { Parameter p = (Parameter) annotation; if (p.names().length == 0) { @@ -490,6 +491,15 @@ public class JCommander { if (p.required()) m_requiredFields.put(f, pd); } } + }else if(delegateAnnotation != null){ + try { + Object delegateObject = f.get(object); + if(delegateObject == null){ + throw new ParameterException("Delegate field '" + f.getName() + "' cannot be null."); + } + addDescription(delegateObject); + } catch (IllegalAccessException e) { + } } } // Traverse the super class until we find Object.class diff --git a/src/main/java/com/beust/jcommander/ParametersDelegate.java b/src/main/java/com/beust/jcommander/ParametersDelegate.java new file mode 100644 index 0000000..5a06f8e --- /dev/null +++ b/src/main/java/com/beust/jcommander/ParametersDelegate.java @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; + +/** + *

When applied to a field all of its child fields annotated + * with {@link Parameter} will be included during arguments + * parsing.

+ * + *

Mainly useful when creating complex command based CLI interfaces, + * where several commands can share a set of arguments, but using + * object inheritance is not enough, due to no-multiple-inheritance + * restriction. Using {@link ParametersDelegate} any number of + * command sets can be shared by using composition pattern.

+ * + *

Delegations can be chained (nested).

+ * + * @author rodionmoiseev + */ +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ FIELD }) +public @interface ParametersDelegate { +} -- cgit v1.2.3 From 3e7cb52cbf4ca537cafb6617b20387225672ad1a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 22 Nov 2011 14:47:22 -0800 Subject: Better handling for fields of type List. --- src/main/java/com/beust/jcommander/JCommander.java | 45 ++++++++++++++++++++-- src/main/java/com/beust/jcommander/Parameter.java | 19 ++++++++- .../jcommander/converters/BigDecimalConverter.java | 2 +- .../converters/CommaParameterSplitter.java | 12 ++++++ .../converters/CommaSeparatedBaseConverter.java | 11 ++++-- .../CommaSeparatedBigDecimalConverter.java | 3 +- .../jcommander/converters/IParameterSplitter.java | 13 +++++++ .../converters/ISO8601DateConverter.java | 3 +- .../internal/DefaultConverterFactory.java | 8 ++-- 9 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java create mode 100644 src/main/java/com/beust/jcommander/converters/IParameterSplitter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d374a6f..0de9004 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -18,6 +18,7 @@ package com.beust.jcommander; +import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; import com.beust.jcommander.internal.DefaultConverterFactory; @@ -1005,21 +1006,25 @@ public class JCommander { public Object convertValue(Field field, Class type, String value) { Parameter annotation = field.getAnnotation(Parameter.class); Class> converterClass = annotation.converter(); + boolean listConverterWasSpecified = annotation.listConverter() != NoConverter.class; // // Try to find a converter on the annotation // - if ( converterClass == null || converterClass == NoConverter.class) { + if (converterClass == null || converterClass == NoConverter.class) { // If no converter specified and type is enum, used enum values to convert if (type.isEnum()){ converterClass = type; } else { converterClass = findConverter(type); } - } + if (converterClass == null) { - converterClass = StringConverter.class; + Type elementType = findFieldGenericType(field); + converterClass = elementType != null + ? findConverter((Class>) elementType) + : StringConverter.class; } // @@ -1051,7 +1056,24 @@ public class JCommander { } } else { converter = instantiateConverter(optionName, converterClass); - result = converter.convert(value); + if (type.isAssignableFrom(List.class) + && field.getGenericType() instanceof ParameterizedType) { + + // The field is a List + if (listConverterWasSpecified) { + // If a list converter was specified, pass the value to it + // for direct conversion + IStringConverter listConverter = + instantiateConverter(optionName, annotation.listConverter()); + result = listConverter.convert(value); + } else { + // No list converter: use the single value converter and pass each + // parsed value to it individually + result = convertToList(value, converter, annotation.splitter()); + } + } else { + result = converter.convert(value); + } } } catch (InstantiationException e) { throw new ParameterException(e); @@ -1064,6 +1086,21 @@ public class JCommander { return result; } + /** + * Use the splitter to split the value into multiple values and then convert + * each of them individually. + */ + private Object convertToList(String value, IStringConverter converter, + Class splitterClass) + throws InstantiationException, IllegalAccessException { + IParameterSplitter splitter = splitterClass.newInstance(); + List result = Lists.newArrayList(); + for (String param : splitter.split(value)) { + result.add(converter.convert(param)); + } + return result; + } + private IStringConverter instantiateConverter(String optionName, Class> converterClass) throws IllegalArgumentException, InstantiationException, IllegalAccessException, diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index c697d2e..1b2a00f 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -20,6 +20,8 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; +import com.beust.jcommander.converters.CommaParameterSplitter; +import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.validators.NoValidator; @@ -65,10 +67,19 @@ public @interface Parameter { boolean password() default false; /** - * The string converter to use for this field. + * The string converter to use for this field. If the field is of type List + * and not listConverter attribute was specified, JCommander will split + * the input in individual values and convert each of them separately. */ Class> converter() default NoConverter.class; + /** + * The list string converter to use for this field. If it's specified, the + * field has to be of type List and the converter needs to return + * a List that's compatible with that type. + */ + Class> listConverter() default NoConverter.class; + /** * If true, this parameter won't appear in the usage(). */ @@ -83,4 +94,10 @@ public @interface Parameter { * @return true if this parameter has a variable arity. See @{IVariableArity} */ boolean variableArity() default false; + + /** + * What splitter to use (applicable only on fields of type List). By default, + * a comma separated splitter will be used. + */ + Class splitter() default CommaParameterSplitter.class; } diff --git a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java index aa8a819..dfbba34 100644 --- a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java +++ b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java @@ -19,6 +19,7 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; + import java.math.BigDecimal; /** @@ -32,7 +33,6 @@ public class BigDecimalConverter extends BaseConverter { super(optionName); } - @Override public BigDecimal convert(String value) { try { return new BigDecimal(value); diff --git a/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java b/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java new file mode 100644 index 0000000..0e3bb18 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.converters; + +import java.util.Arrays; +import java.util.List; + +public class CommaParameterSplitter implements IParameterSplitter { + + public List split(String value) { + return Arrays.asList(value.split(",")); + } + +} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java index 454bca6..7f2d5b0 100644 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java @@ -19,11 +19,13 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; + import java.util.ArrayList; import java.util.List; /** - * Base class for comma-separated converters which stores the name of the option and object type in case of errors. + * Base class for comma-separated converters which stores the name of the option + * and object type in case of errors. * * @author Angus Smithson */ @@ -40,9 +42,12 @@ abstract class CommaSeparatedBaseConverter extends BaseConverter> { ArrayList al = new ArrayList(); final String[] values = value.split(","); try { - for (String s : values) al.add(getIndividualValue(s)); + for (String s : values) { + al.add(getIndividualValue(s)); + } } catch (Throwable t) { - throw new ParameterException(getErrorString(value, String.format("a list of type %s.", m_typeDescription))); + throw new ParameterException(getErrorString(value, + String.format("a list of type %s.", m_typeDescription))); } return al; } diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java index dae58c2..c546a3b 100644 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java +++ b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java @@ -25,7 +25,8 @@ import java.math.BigDecimal; * * @author Angus Smithson */ -public class CommaSeparatedBigDecimalConverter extends CommaSeparatedBaseConverter { +public class CommaSeparatedBigDecimalConverter extends + CommaSeparatedBaseConverter { public CommaSeparatedBigDecimalConverter(String optionName) { super(optionName, "BigDecimal"); diff --git a/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java new file mode 100644 index 0000000..e8b87b0 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java @@ -0,0 +1,13 @@ +package com.beust.jcommander.converters; + +import java.util.List; + +/** + * Convert a string representing several parameters (e.g. "a,b,c" or "d/e/f") into a + * list of arguments ([a,b,c] and [d,e,f]). + * + * @param + */ +public interface IParameterSplitter { + List split(String value); +} diff --git a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java index 7429e0f..f024f5c 100644 --- a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java +++ b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java @@ -19,7 +19,7 @@ package com.beust.jcommander.converters; import com.beust.jcommander.ParameterException; -import com.beust.jcommander.converters.BaseConverter; + import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; @@ -38,7 +38,6 @@ public class ISO8601DateConverter extends BaseConverter { super(optionName); } - @Override public Date convert(String value) { try { return DATE_FORMAT.parse(value); diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index fed5783..f98a111 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -20,15 +20,15 @@ package com.beust.jcommander.internal; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.IStringConverterFactory; +import com.beust.jcommander.converters.BigDecimalConverter; import com.beust.jcommander.converters.BooleanConverter; +import com.beust.jcommander.converters.DoubleConverter; import com.beust.jcommander.converters.FileConverter; +import com.beust.jcommander.converters.FloatConverter; +import com.beust.jcommander.converters.ISO8601DateConverter; import com.beust.jcommander.converters.IntegerConverter; import com.beust.jcommander.converters.LongConverter; -import com.beust.jcommander.converters.FloatConverter; -import com.beust.jcommander.converters.DoubleConverter; import com.beust.jcommander.converters.StringConverter; -import com.beust.jcommander.converters.BigDecimalConverter; -import com.beust.jcommander.converters.ISO8601DateConverter; import java.io.File; import java.math.BigDecimal; -- cgit v1.2.3 From cc5c9d85d71efdc2a2abe23bfa8a3f6afbec9fe1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 22 Nov 2011 14:50:58 -0800 Subject: Clean up. --- src/main/java/com/beust/jcommander/JCommander.java | 15 ++++++ .../converters/CommaSeparatedBaseConverter.java | 56 ---------------------- .../CommaSeparatedBigDecimalConverter.java | 39 --------------- .../converters/CommaSeparatedIntConverter.java | 36 -------------- .../converters/CommaSeparatedStringConverter.java | 36 -------------- 5 files changed, 15 insertions(+), 167 deletions(-) delete mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java delete mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java delete mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java delete mode 100644 src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0de9004..66a477d 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -612,6 +612,21 @@ public class JCommander { } + /** + * @return the generic type of the collection for this field, or null if not applicable. + */ + private Type findFieldGenericType(Field field) { + if (field.getGenericType() instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) field.getGenericType(); + Type cls = p.getActualTypeArguments()[0]; + if (cls instanceof Class) { + return cls; + } + } + + return null; + } + /** * @return the number of options that were processed. */ diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java deleted file mode 100644 index 7f2d5b0..0000000 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBaseConverter.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.beust.jcommander.converters; - -import com.beust.jcommander.ParameterException; - -import java.util.ArrayList; -import java.util.List; - -/** - * Base class for comma-separated converters which stores the name of the option - * and object type in case of errors. - * - * @author Angus Smithson - */ -abstract class CommaSeparatedBaseConverter extends BaseConverter> { - - private String m_typeDescription; - - public CommaSeparatedBaseConverter(String optionName, String typeDescription) { - super(optionName); - m_typeDescription = typeDescription; - } - - public List convert(String value) { - ArrayList al = new ArrayList(); - final String[] values = value.split(","); - try { - for (String s : values) { - al.add(getIndividualValue(s)); - } - } catch (Throwable t) { - throw new ParameterException(getErrorString(value, - String.format("a list of type %s.", m_typeDescription))); - } - return al; - } - - abstract T getIndividualValue(String value); -} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java deleted file mode 100644 index c546a3b..0000000 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedBigDecimalConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.beust.jcommander.converters; - -import java.math.BigDecimal; - -/** - * Convert a string of comma separated numbers into a list of type BigDecimal. - * - * @author Angus Smithson - */ -public class CommaSeparatedBigDecimalConverter extends - CommaSeparatedBaseConverter { - - public CommaSeparatedBigDecimalConverter(String optionName) { - super(optionName, "BigDecimal"); - } - - @Override - BigDecimal getIndividualValue(String value) { - return new BigDecimal(value); - } -} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java deleted file mode 100644 index dc98ecc..0000000 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedIntConverter.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.beust.jcommander.converters; - -/** - * Convert a string of comma separated numbers into a list of type Integer. - * - * @author Angus Smithson - */ -public class CommaSeparatedIntConverter extends CommaSeparatedBaseConverter { - - public CommaSeparatedIntConverter(String optionName) { - super(optionName, "Integer"); - } - - @Override - Integer getIndividualValue(String value) { - return Integer.parseInt(value); - } -} diff --git a/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java b/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java deleted file mode 100644 index a5cddf7..0000000 --- a/src/main/java/com/beust/jcommander/converters/CommaSeparatedStringConverter.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.beust.jcommander.converters; - -/** - * Convert a string of comma separated words into a list of type String. - * - * @author Angus Smithson - */ -public class CommaSeparatedStringConverter extends CommaSeparatedBaseConverter { - - public CommaSeparatedStringConverter(String optionName) { - super(optionName, "String"); - } - - @Override - String getIndividualValue(String value) { - return value; - } -} -- cgit v1.2.3 From 3cf4188ad5c30c66b359353289ac2d03967d6cf8 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 23 Nov 2011 12:54:13 -0800 Subject: Added {set,get}ColumnSize() for the usage. --- src/main/java/com/beust/jcommander/JCommander.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 66a477d..3739585 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -144,6 +144,8 @@ public class JCommander { } }; + private int m_columnSize = 79; + /** * The factories used to look up string converters. */ @@ -939,8 +941,16 @@ public class JCommander { m_parameterDescriptionComparator = c; } + public void setColumnSize(int columnSize) { + m_columnSize = columnSize; + } + + public int getColumnSize() { + return m_columnSize; + } + private void wrapDescription(StringBuilder out, int indent, String description) { - int max = 79; + int max = getColumnSize(); String[] words = description.split(" "); int current = indent; int i = 0; -- cgit v1.2.3 From 66e78950950fa85f88043ebc7c2b2dc9aa0814af Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 23 Nov 2011 13:15:16 -0800 Subject: Added: @Parameter(commandNames) so that command names can be specified with annotations --- src/main/java/com/beust/jcommander/JCommander.java | 15 ++++++++++++++- src/main/java/com/beust/jcommander/Parameters.java | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3739585..a3beecb 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1157,6 +1157,18 @@ public class JCommander { addCommand(name, object, new String[0]); } + public void addCommand(Object object) { + Parameters p = object.getClass().getAnnotation(Parameters.class); + if (p != null && p.commandNames().length > 0) { + for (String commandName : p.commandNames()) { + addCommand(commandName, object); + } + } else { + throw new ParameterException("Trying to add command " + object.getClass().getName() + + " without specifying its names in @Parameters"); + } + } + /** * Add a command object and its aliases. */ @@ -1312,6 +1324,7 @@ public class JCommander { @Override public String toString() { return getDisplayName(); + } } -} +} \ No newline at end of file diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index e25d1f2..be5b5ce 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -60,4 +60,9 @@ public @interface Parameters { * @return the key used to find the command description in the resource bundle. */ String commandDescriptionKey() default ""; + + /** + * An array of allowed command names. + */ + String[] commandNames() default {}; } -- cgit v1.2.3 From b871944ccc7f31a310f0d6b2e1568ac6656f2bec Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 25 Nov 2011 09:17:47 -0800 Subject: ParametersDelegate: doc and some minor formatting. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 2720a58..3848dda 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -494,10 +494,10 @@ public class JCommander { if (p.required()) m_requiredFields.put(f, pd); } } - }else if(delegateAnnotation != null){ + } else if (delegateAnnotation != null) { try { Object delegateObject = f.get(object); - if(delegateObject == null){ + if (delegateObject == null){ throw new ParameterException("Delegate field '" + f.getName() + "' cannot be null."); } addDescription(delegateObject); -- cgit v1.2.3 From 4ba2a3c6a66626c4629266729a16e7f7e07b9ad0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 25 Nov 2011 09:34:05 -0800 Subject: Fixed: Throw if an unknown option is found --- src/main/java/com/beust/jcommander/JCommander.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3848dda..99b2606 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -569,6 +569,8 @@ public class JCommander { } } } + } else { + throw new ParameterException("Unknown option: " + arg); } } else { -- cgit v1.2.3 From c3507ebf6d4b118ebeb443f0da87a63543ab395a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 25 Nov 2011 10:47:01 -0800 Subject: Fixed: Main parameters are now validated as well (Connor Mullen). --- src/main/java/com/beust/jcommander/JCommander.java | 2 ++ .../com/beust/jcommander/ParameterDescription.java | 26 +++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 99b2606..65c59fc 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -594,6 +594,8 @@ public class JCommander { } } + ParameterDescription.validateParameter(m_mainParameterAnnotation, "Default", value); + m_mainParameterDescription.setAssigned(true); mp.add(convertedValue); } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 5b674ca..37376e7 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -31,8 +31,6 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import com.beust.jcommander.validators.NoValidator; - public class ParameterDescription { private Object m_object; private Parameter m_parameterAnnotation; @@ -221,16 +219,18 @@ public class ParameterDescription { } private void validateParameter(String name, String value) { - Class validator = m_parameterAnnotation.validateWith(); - if (validator != NoValidator.class) { - try { - p("Validating parameter:" + name + " value:" + value + " validator:" + validator); - validator.newInstance().validate(name, value); - } catch (InstantiationException e) { - throw new ParameterException("Can't instantiate validator:" + e); - } catch (IllegalAccessException e) { - throw new ParameterException("Can't instantiate validator:" + e); - } + validateParameter(m_parameterAnnotation, name, value); + } + + public static void validateParameter(Parameter annotation, String name, String value) { + Class validator = annotation.validateWith(); + try { + p("Validating parameter:" + name + " value:" + value + " validator:" + validator); + validator.newInstance().validate(name, value); + } catch (InstantiationException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } catch (IllegalAccessException e) { + throw new ParameterException("Can't instantiate validator:" + e); } } @@ -260,7 +260,7 @@ public class ParameterDescription { return (!isDefault && !m_assigned); } - private void p(String string) { + private static void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { System.out.println("[ParameterDescription] " + string); } -- cgit v1.2.3 From e45913e4d99699a0860df6a3aa7e2007750ec45f Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Tue, 29 Nov 2011 09:40:08 +0100 Subject: Issue #86: Use Console() when possible instead of System.out to preserve non ascii chars. --- src/main/java/com/beust/jcommander/JCommander.java | 56 ++++++++++------------ .../com/beust/jcommander/ParameterDescription.java | 4 +- .../com/beust/jcommander/internal/Console.java | 10 ++++ .../beust/jcommander/internal/DefaultConsole.java | 33 +++++++++++++ .../com/beust/jcommander/internal/JDK6Console.java | 38 +++++++++++++++ 5 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/internal/Console.java create mode 100644 src/main/java/com/beust/jcommander/internal/DefaultConsole.java create mode 100644 src/main/java/com/beust/jcommander/internal/JDK6Console.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 65c59fc..9962b2f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -21,14 +21,16 @@ package com.beust.jcommander; import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; +import com.beust.jcommander.internal.Console; +import com.beust.jcommander.internal.DefaultConsole; import com.beust.jcommander.internal.DefaultConverterFactory; +import com.beust.jcommander.internal.JDK6Console; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; -import java.io.InputStreamReader; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -145,6 +147,8 @@ public class JCommander { }; private int m_columnSize = 79; + + private static Console m_console; /** * The factories used to look up string converters. @@ -197,6 +201,19 @@ public class JCommander { addObject(object); parse(args); } + + public static Console getConsole() { + if (m_console == null) { + try { + Method consoleMethod = System.class.getDeclaredMethod("console", new Class[0]); + Object console = consoleMethod.invoke(null, new Object[0]); + m_console = new JDK6Console(console); + } catch (Throwable t) { + m_console = new DefaultConsole(); + } + } + return m_console; + } /** * Adds the provided arg object to the set of objects that this commander @@ -701,31 +718,8 @@ public class JCommander { * on Java 6. */ private char[] readPassword(String description) { - System.out.print(description + ": "); - try { - Method consoleMethod = System.class.getDeclaredMethod("console", new Class[0]); - Object console = consoleMethod.invoke(null, new Object[0]); - Method readPassword = console.getClass().getDeclaredMethod("readPassword", new Class[0]); - return (char[]) readPassword.invoke(console, new Object[0]); - } catch (Throwable t) { - return readLine(description); - } - } - - /** - * Read a line from stdin (used when java.io.Console is not available) - */ - private char[] readLine(String description) { - try { - InputStreamReader isr = new InputStreamReader(System.in); - BufferedReader in = new BufferedReader(isr); - String result = in.readLine(); - in.close(); - isr.close(); - return result.toCharArray(); - } catch (IOException e) { - throw new ParameterException(e); - } + getConsole().print(description + ": "); + return getConsole().readPassword(); } private String[] subArray(String[] args, int index) { @@ -808,7 +802,7 @@ public class JCommander { public void usage(String commandName) { StringBuilder sb = new StringBuilder(); usage(commandName, sb); - System.out.println(sb.toString()); + getConsole().println(sb.toString()); } /** @@ -858,12 +852,12 @@ public class JCommander { } /** - * Display a the help on System.out. + * Display the help on System.out. */ public void usage() { StringBuilder sb = new StringBuilder(); usage(sb); - System.out.println(sb.toString()); + getConsole().println(sb.toString()); } /** @@ -1005,7 +999,7 @@ public class JCommander { private void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { - System.out.println("[JCommander] " + string); + getConsole().println("[JCommander] " + string); } } @@ -1305,7 +1299,7 @@ public class JCommander { } return sb.toString(); } - + @Override public int hashCode() { final int prime = 31; diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 37376e7..0d85a6a 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -91,7 +91,7 @@ public class ParameterDescription { if (m_bundle != null) { m_description = m_bundle.getString(annotation.descriptionKey()); } else { -// System.out.println("Warning: field " + object.getClass() + "." + field.getName() +// JCommander.getConsole().println("Warning: field " + object.getClass() + "." + field.getName() // + " has a descriptionKey but no bundle was defined with @ResourceBundle, using " + // "default description:'" + m_description + "'"); } @@ -262,7 +262,7 @@ public class ParameterDescription { private static void p(String string) { if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { - System.out.println("[ParameterDescription] " + string); + JCommander.getConsole().println("[ParameterDescription] " + string); } } diff --git a/src/main/java/com/beust/jcommander/internal/Console.java b/src/main/java/com/beust/jcommander/internal/Console.java new file mode 100644 index 0000000..e2bddb3 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/Console.java @@ -0,0 +1,10 @@ +package com.beust.jcommander.internal; + +public interface Console { + + void print(String msg); + + void println(String msg); + + char[] readPassword(); +} diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java new file mode 100644 index 0000000..b838610 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java @@ -0,0 +1,33 @@ +package com.beust.jcommander.internal; + +import com.beust.jcommander.ParameterException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class DefaultConsole implements Console { + + public void print(String msg) { + System.out.print(msg); + } + + public void println(String msg) { + System.out.println(msg); + } + + public char[] readPassword() { + try { + InputStreamReader isr = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(isr); + String result = in.readLine(); + in.close(); + isr.close(); + return result.toCharArray(); + } + catch (IOException e) { + throw new ParameterException(e); + } + } + +} diff --git a/src/main/java/com/beust/jcommander/internal/JDK6Console.java b/src/main/java/com/beust/jcommander/internal/JDK6Console.java new file mode 100644 index 0000000..f0c60d2 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/JDK6Console.java @@ -0,0 +1,38 @@ +package com.beust.jcommander.internal; + +import com.beust.jcommander.ParameterException; + +import java.io.PrintWriter; +import java.lang.reflect.Method; + +public class JDK6Console implements Console { + + private Object console; + + private PrintWriter writer; + + public JDK6Console(Object console) throws Exception { + this.console = console; + Method writerMethod = console.getClass().getDeclaredMethod("writer", new Class[0]); + writer = (PrintWriter) writerMethod.invoke(console, new Object[0]); + } + + public void print(String msg) { + writer.print(msg); + } + + public void println(String msg) { + writer.println(msg); + } + + public char[] readPassword() { + try { + Method readPasswordMethod = console.getClass().getDeclaredMethod("readPassword", new Class[0]); + return (char[]) readPasswordMethod.invoke(console, new Object[0]); + } + catch (Exception e) { + throw new ParameterException(e); + } + } + +} -- cgit v1.2.3 From 932e1670f1993a228a0d85c8b27cfd4a6a065f6c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 10 Jan 2012 15:13:29 -0800 Subject: First step implementing DynamicParameter. --- .../com/beust/jcommander/DynamicParameter.java | 37 +++++++++++++++ src/main/java/com/beust/jcommander/JCommander.java | 23 ++++++++++ .../com/beust/jcommander/ParameterDescription.java | 52 +++++++++++++++------- .../java/com/beust/jcommander/internal/Maps.java | 8 ++++ 4 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/DynamicParameter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java new file mode 100644 index 0000000..52a725c --- /dev/null +++ b/src/main/java/com/beust/jcommander/DynamicParameter.java @@ -0,0 +1,37 @@ +package com.beust.jcommander; + +import static java.lang.annotation.ElementType.FIELD; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({ FIELD }) +public @interface DynamicParameter { + /** + * An array of allowed command line parameters (e.g. "-D", "--define", etc...). + */ + String[] names() default {}; + + /** + * How many parameter values this parameter will consume. For example, + * an arity of 0 allow "-Da=b", 1 allows "-D a=b" and 2, "-D a b". Larger + * arities are not allowed for dynamic parameters. + */ + int arity() default -1; + + /** + * Whether this option is required. + */ + boolean required() default false; + + /** + * A description of this option. + */ + String description() default ""; + + /** + * The key used to find the string in the message bundle. + */ + String descriptionKey() default ""; +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9962b2f..6558d9e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -486,7 +486,11 @@ public class JCommander { f.setAccessible(true); Annotation annotation = f.getAnnotation(Parameter.class); Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class); + Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class); if (annotation != null) { + // + // @Parameter + // Parameter p = (Parameter) annotation; if (p.names().length == 0) { p("Found main parameter:" + f); @@ -512,6 +516,9 @@ public class JCommander { } } } else if (delegateAnnotation != null) { + // + // @ParametersDelegate + // try { Object delegateObject = f.get(object); if (delegateObject == null){ @@ -520,6 +527,22 @@ public class JCommander { addDescription(delegateObject); } catch (IllegalAccessException e) { } + } else if (dynamicParameter != null) { + // + // @DynamicParameter + // + DynamicParameter dp = (DynamicParameter) dynamicParameter; + for (String name : dp.names()) { + if (m_descriptions.containsKey(name)) { + throw new ParameterException("Found the option " + name + " multiple times"); + } + p("Adding description for " + name); + ParameterDescription pd = new ParameterDescription(object, dp, f, m_bundle, this); + m_fields.put(f, pd); + m_descriptions.put(name, pd); + + if (dp.required()) m_requiredFields.put(f, pd); + } } } // Traverse the super class until we find Object.class diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 0d85a6a..af035dd 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -34,6 +34,7 @@ import java.util.TreeSet; public class ParameterDescription { private Object m_object; private Parameter m_parameterAnnotation; + private DynamicParameter m_dynamicParameterAnnotation; private Field m_field; /** Keep track of whether a value was added to flag an error */ private boolean m_assigned = false; @@ -44,9 +45,16 @@ public class ParameterDescription { /** Longest of the names(), used to present usage() alphabetically */ private String m_longestName = ""; + public ParameterDescription(Object object, DynamicParameter annotation, Field field, + ResourceBundle bundle, JCommander jc) { + m_dynamicParameterAnnotation = annotation; + init(object, field, bundle, jc); + } + public ParameterDescription(Object object, Parameter annotation, Field field, ResourceBundle bundle, JCommander jc) { - init(object, annotation, field, bundle, jc); + m_parameterAnnotation = annotation; + init(object, field, bundle, jc); } /** @@ -75,21 +83,11 @@ public class ParameterDescription { return s == null || "".equals(s); } - private void init(Object object, Parameter annotation, Field field, ResourceBundle bundle, - JCommander jCommander) { - m_object = object; - m_parameterAnnotation = annotation; - m_field = field; - m_bundle = bundle; - if (m_bundle == null) { - m_bundle = findResourceBundle(object); - } - m_jCommander = jCommander; - - m_description = annotation.description(); - if (! "".equals(annotation.descriptionKey())) { + private void initDescription(String description, String descriptionKey, String[] names) { + m_description = description; + if (! "".equals(descriptionKey)) { if (m_bundle != null) { - m_description = m_bundle.getString(annotation.descriptionKey()); + m_description = m_bundle.getString(descriptionKey); } else { // JCommander.getConsole().println("Warning: field " + object.getClass() + "." + field.getName() // + " has a descriptionKey but no bundle was defined with @ResourceBundle, using " + @@ -97,9 +95,31 @@ public class ParameterDescription { } } - for (String name : annotation.names()) { + for (String name : names) { if (name.length() > m_longestName.length()) m_longestName = name; } + } + + private void init(Object object, Field field, ResourceBundle bundle, + JCommander jCommander) { + m_object = object; + m_field = field; + m_bundle = bundle; + if (m_bundle == null) { + m_bundle = findResourceBundle(object); + } + m_jCommander = jCommander; + + if (m_parameterAnnotation != null) { + initDescription(m_parameterAnnotation.description(), m_parameterAnnotation.descriptionKey(), + m_parameterAnnotation.names()); + } else if (m_dynamicParameterAnnotation != null) { + initDescription(m_dynamicParameterAnnotation.description(), + m_dynamicParameterAnnotation.descriptionKey(), + m_dynamicParameterAnnotation.names()); + } else { + throw new AssertionError("Shound never happen"); + } try { m_default = m_field.get(m_object); diff --git a/src/main/java/com/beust/jcommander/internal/Maps.java b/src/main/java/com/beust/jcommander/internal/Maps.java index 9238aaa..e272122 100644 --- a/src/main/java/com/beust/jcommander/internal/Maps.java +++ b/src/main/java/com/beust/jcommander/internal/Maps.java @@ -32,4 +32,12 @@ public class Maps { return new LinkedHashMap(); } + public static Map newHashMap(T... parameters) { + Map result = Maps.newHashMap(); + for (int i = 0; i < parameters.length; i += 2) { + result.put(parameters[i], parameters[i + 1]); + } + return result; + } + } -- cgit v1.2.3 From 78db59cfd11a5a1fb2eb4602f246b63dea91bf93 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 10 Jan 2012 15:28:43 -0800 Subject: More DynamicParameter work. --- .../com/beust/jcommander/DynamicParameter.java | 5 +++ .../com/beust/jcommander/ParameterDescription.java | 22 ++++++++---- .../com/beust/jcommander/WrappedParameter.java | 41 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/WrappedParameter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java index 52a725c..642ab55 100644 --- a/src/main/java/com/beust/jcommander/DynamicParameter.java +++ b/src/main/java/com/beust/jcommander/DynamicParameter.java @@ -34,4 +34,9 @@ public @interface DynamicParameter { * The key used to find the string in the message bundle. */ String descriptionKey() default ""; + + /** + * If true, this parameter won't appear in the usage(). + */ + boolean hidden() default false; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index af035dd..524b2fa 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -33,8 +33,11 @@ import java.util.TreeSet; public class ParameterDescription { private Object m_object; + + private WrappedParameter m_wrappedParameter; private Parameter m_parameterAnnotation; private DynamicParameter m_dynamicParameterAnnotation; + private Field m_field; /** Keep track of whether a value was added to flag an error */ private boolean m_assigned = false; @@ -48,12 +51,14 @@ public class ParameterDescription { public ParameterDescription(Object object, DynamicParameter annotation, Field field, ResourceBundle bundle, JCommander jc) { m_dynamicParameterAnnotation = annotation; + m_wrappedParameter = new WrappedParameter(m_dynamicParameterAnnotation); init(object, field, bundle, jc); } public ParameterDescription(Object object, Parameter annotation, Field field, ResourceBundle bundle, JCommander jc) { m_parameterAnnotation = annotation; + m_wrappedParameter = new WrappedParameter(m_parameterAnnotation); init(object, field, bundle, jc); } @@ -130,12 +135,17 @@ public class ParameterDescription { // Validate default values, if any and if applicable // if (m_default != null) { - String[] names = m_parameterAnnotation.names(); - String name = names.length > 0 ? names[0] : ""; - validateParameter(name, m_default.toString()); + if (m_parameterAnnotation != null) { + validateDefaultValues(m_parameterAnnotation.names()); + } } } + private void validateDefaultValues(String[] names) { + String name = names.length > 0 ? names[0] : ""; + validateParameter(name, m_default.toString()); + } + public String getLongestName() { return m_longestName; } @@ -163,8 +173,8 @@ public class ParameterDescription { return sb.toString(); } - public Parameter getParameter() { - return m_parameterAnnotation; + WrappedParameter getParameter() { + return m_wrappedParameter; } public Field getField() { @@ -200,7 +210,7 @@ public class ParameterDescription { public void addValue(String value, boolean isDefault) { p("Adding " + (isDefault ? "default " : "") + "value:" + value + " to parameter:" + m_field.getName()); - String name = m_parameterAnnotation.names()[0]; + String name = m_wrappedParameter.names()[0]; if (m_assigned && ! isMultiOption()) { throw new ParameterException("Can only specify option " + name + " once."); diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java new file mode 100644 index 0000000..59beb15 --- /dev/null +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -0,0 +1,41 @@ +package com.beust.jcommander; + +/** + * Encapsulates the operations common to @Parameter and @DynamicParameter + */ +public class WrappedParameter { + private Parameter m_parameter; + private DynamicParameter m_dynamicParameter; + + public WrappedParameter(Parameter p) { + m_parameter = p; + } + + public WrappedParameter(DynamicParameter p) { + m_dynamicParameter = p; + } + + public int arity() { + return m_parameter != null ? m_parameter.arity() : m_dynamicParameter.arity(); + } + + public boolean hidden() { + return m_parameter != null ? m_parameter.hidden() : m_dynamicParameter.hidden(); + } + + public boolean required() { + return m_parameter != null ? m_parameter.required() : m_dynamicParameter.required(); + } + + public boolean password() { + return m_parameter != null ? m_parameter.password() : false; + } + + public String[] names() { + return m_parameter != null ? m_parameter.names() : m_dynamicParameter.names(); + } + + public boolean variableArity() { + return m_parameter != null ? m_parameter.variableArity() : false; + } +} -- cgit v1.2.3 From 043d359ca700da0f541f849157d7db2b1b6f93fb Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 10 Jan 2012 16:07:21 -0800 Subject: Working @DynamicParameter. --- .../com/beust/jcommander/DynamicParameter.java | 12 ++++++ src/main/java/com/beust/jcommander/JCommander.java | 7 +++- .../com/beust/jcommander/ParameterDescription.java | 25 +++++++++--- .../com/beust/jcommander/WrappedParameter.java | 44 ++++++++++++++++++++++ 4 files changed, 81 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java index 642ab55..32b68b4 100644 --- a/src/main/java/com/beust/jcommander/DynamicParameter.java +++ b/src/main/java/com/beust/jcommander/DynamicParameter.java @@ -2,6 +2,8 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; +import com.beust.jcommander.validators.NoValidator; + import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -39,4 +41,14 @@ public @interface DynamicParameter { * If true, this parameter won't appear in the usage(). */ boolean hidden() default false; + + /** + * The validation class to use. + */ + Class validateWith() default NoValidator.class; + + /** + * The character(s) used to assign the values. + */ + String assignment() default "="; } diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 6558d9e..ce138b4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -634,7 +634,8 @@ public class JCommander { } } - ParameterDescription.validateParameter(m_mainParameterAnnotation, "Default", value); + ParameterDescription.validateParameter(m_mainParameterAnnotation.validateWith(), + "Default", value); m_mainParameterDescription.setAssigned(true); mp.add(convertedValue); @@ -1061,6 +1062,10 @@ public class JCommander { */ public Object convertValue(Field field, Class type, String value) { Parameter annotation = field.getAnnotation(Parameter.class); + + // Do nothing if it's a @DynamicParameter + if (annotation == null) return value; + Class> converterClass = annotation.converter(); boolean listConverterWasSpecified = annotation.listConverter() != NoConverter.class; diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 524b2fa..7c83824 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -18,7 +18,6 @@ package com.beust.jcommander; - import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; @@ -26,6 +25,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.SortedSet; @@ -50,6 +50,11 @@ public class ParameterDescription { public ParameterDescription(Object object, DynamicParameter annotation, Field field, ResourceBundle bundle, JCommander jc) { + if (! Map.class.isAssignableFrom(field.getType())) { + throw new ParameterException("@DynamicParameter " + field.getName() + " should be of type " + + "Map but is " + field.getType().getName()); + } + m_dynamicParameterAnnotation = annotation; m_wrappedParameter = new WrappedParameter(m_dynamicParameterAnnotation); init(object, field, bundle, jc); @@ -183,7 +188,12 @@ public class ParameterDescription { private boolean isMultiOption() { Class fieldType = m_field.getType(); - return fieldType.equals(List.class) || fieldType.equals(Set.class); + return fieldType.equals(List.class) || fieldType.equals(Set.class) + || isDynamicParameter(m_field); + } + + private boolean isDynamicParameter(Field field) { + return field.getAnnotation(DynamicParameter.class) != null; } public void addValue(String value) { @@ -239,7 +249,7 @@ public class ParameterDescription { // l. } } else { - m_field.set(m_object, convertedValue); + m_wrappedParameter.addValue(m_field, m_object, convertedValue); } if (! isDefault) m_assigned = true; } @@ -249,11 +259,14 @@ public class ParameterDescription { } private void validateParameter(String name, String value) { - validateParameter(m_parameterAnnotation, name, value); + Class validator = m_wrappedParameter.validateWith(); + if (validator != null) { + validateParameter(validator, name, value); + } } - public static void validateParameter(Parameter annotation, String name, String value) { - Class validator = annotation.validateWith(); + public static void validateParameter(Class validator, + String name, String value) { try { p("Validating parameter:" + name + " value:" + value + " validator:" + validator); validator.newInstance().validate(name, value); diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index 59beb15..f603880 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -1,5 +1,9 @@ package com.beust.jcommander; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** * Encapsulates the operations common to @Parameter and @DynamicParameter */ @@ -38,4 +42,44 @@ public class WrappedParameter { public boolean variableArity() { return m_parameter != null ? m_parameter.variableArity() : false; } + + public Class validateWith() { + return m_parameter != null ? m_parameter.validateWith() : m_dynamicParameter.validateWith(); + } + + public void addValue(Field field, Object object, Object value) + throws IllegalArgumentException, IllegalAccessException { + if (m_parameter != null) { + field.set(object, value); + } else { + String a = m_dynamicParameter.assignment(); + String sv = value.toString(); + String[] kv = sv.split(a); + if (kv.length != 2) { + throw new ParameterException("Dynamic parameter expected a value of the form a" + a + "b" + + " but got:" + sv); + } + callPut(object, field, kv[0], kv[1]); + } + } + + private void callPut(Object object, Field field, String key, String value) { + try { + Method m; + m = findPut(field.getType()); + m.invoke(field.get(object), key, value); + } catch (SecurityException e) { + e.printStackTrace(); + } catch(IllegalAccessException e) { + e.printStackTrace(); + } catch(InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + + private Method findPut(Class cls) throws SecurityException, NoSuchMethodException { + return cls.getMethod("put", Object.class, Object.class); + } } -- cgit v1.2.3 From 7e743acbff5277d087347bfba2409406865af8a0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 10 Jan 2012 16:48:33 -0800 Subject: Automatic handling of arities for @DynamicParameter. --- .../java/com/beust/jcommander/DynamicParameter.java | 7 ------- src/main/java/com/beust/jcommander/JCommander.java | 18 ++++++++++++++++-- .../com/beust/jcommander/ParameterDescription.java | 4 ++++ .../java/com/beust/jcommander/WrappedParameter.java | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java index 32b68b4..77b8632 100644 --- a/src/main/java/com/beust/jcommander/DynamicParameter.java +++ b/src/main/java/com/beust/jcommander/DynamicParameter.java @@ -15,13 +15,6 @@ public @interface DynamicParameter { */ String[] names() default {}; - /** - * How many parameter values this parameter will consume. For example, - * an arity of 0 allow "-Da=b", 1 allows "-D a=b" and 2, "-D a b". Larger - * arities are not allowed for dynamic parameters. - */ - int arity() default -1; - /** * Whether this option is required. */ diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index ce138b4..d94c3df 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -338,11 +338,11 @@ public class JCommander { vResult1.addAll(readFile(fileName)); } else { - vResult1.add(arg); + List expanded = expandDynamicArg(arg); + vResult1.addAll(expanded); } } - // // Expand separators // List vResult2 = Lists.newArrayList(); @@ -367,6 +367,20 @@ public class JCommander { return vResult2.toArray(new String[vResult2.size()]); } + private List expandDynamicArg(String arg) { + for (ParameterDescription pd : m_descriptions.values()) { + if (pd.isDynamicParameter()) { + for (String name : pd.getParameter().names()) { + if (arg.startsWith(name) && !arg.equals(name)) { + return Arrays.asList(name, arg.substring(name.length())); + } + } + } + } + + return Arrays.asList(arg); + } + private boolean isOption(String[] args, String arg) { String prefixes = getOptionPrefixes(args, arg); return prefixes.indexOf(arg.charAt(0)) >= 0; diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 7c83824..008e12a 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -313,4 +313,8 @@ public class ParameterDescription { public String toString() { return "[ParameterDescription " + m_field.getName() + "]"; } + + public boolean isDynamicParameter() { + return m_dynamicParameterAnnotation != null; + } } diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index f603880..a9b3df5 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -20,7 +20,7 @@ public class WrappedParameter { } public int arity() { - return m_parameter != null ? m_parameter.arity() : m_dynamicParameter.arity(); + return m_parameter != null ? m_parameter.arity() : 1; } public boolean hidden() { -- cgit v1.2.3 From e923414889a04be46c131af01dbe466d10f10721 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 11 Jan 2012 10:22:37 -0800 Subject: Fixed NPE in usage(). --- src/main/java/com/beust/jcommander/ParameterDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 008e12a..bf2f3c7 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -169,7 +169,7 @@ public class ParameterDescription { public String getNames() { StringBuilder sb = new StringBuilder(); - String[] names = m_parameterAnnotation.names(); + String[] names = m_wrappedParameter.names(); for (int i = 0; i < names.length; i++) { if (i > 0) sb.append(", "); if (names.length == 1 && names[i].startsWith("--")) sb.append(" "); -- cgit v1.2.3 From ef85e832405933f6897893581a3df908e9e2a432 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 11 Jan 2012 12:35:22 -0800 Subject: Show the dynamic parameter syntax in the usage. --- src/main/java/com/beust/jcommander/JCommander.java | 15 ++++++++++++--- src/main/java/com/beust/jcommander/WrappedParameter.java | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index d94c3df..e2ca5a6 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -949,14 +949,23 @@ public class JCommander { int l = pd.getNames().length(); int spaceCount = longestName - l; int start = out.length(); + WrappedParameter parameter = pd.getParameter(); out.append(indent).append(" " - + (pd.getParameter().required() ? "* " : " ") + + (parameter.required() ? "* " : " ") + pd.getNames() + s(spaceCount)); int indentCount = out.length() - start; wrapDescription(out, indentCount, pd.getDescription()); Object def = pd.getDefault(); - if (def != null) out.append("\n" + spaces(indentCount + 1)) - .append("Default: " + def); + if (pd.isDynamicParameter()) { + out.append("\n" + spaces(indentCount + 1)) + .append("Syntax: " + parameter.names()[0] + + "key" + parameter.getAssignment() + + "value"); + } + if (def != null && ! "".equals(def)) { + out.append("\n" + spaces(indentCount + 1)) + .append("Default: " + def); + } out.append("\n"); } diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index a9b3df5..bba888f 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -82,4 +82,8 @@ public class WrappedParameter { private Method findPut(Class cls) throws SecurityException, NoSuchMethodException { return cls.getMethod("put", Object.class, Object.class); } + + public String getAssignment() { + return m_dynamicParameter != null ? m_dynamicParameter.assignment() : ""; + } } -- cgit v1.2.3 From 8ad02daa23243bf515009d16205465f1b811da81 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 12 Jan 2012 13:23:58 -0800 Subject: Fixed: Commands with same prefix as options were not working properly. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e2ca5a6..cfa23e1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -587,7 +587,8 @@ public class JCommander { String a = trim(arg); p("Parsing arg:" + a); - if (isOption(args, a)) { + JCommander jc = findCommandByAlias(arg); + if (isOption(args, a) && jc == null) { // // Option // @@ -658,7 +659,6 @@ public class JCommander { // // Command parsing // - JCommander jc = findCommandByAlias(arg); if (jc == null) throw new MissingCommandException("Expected a command, got " + arg); m_parsedCommand = jc.m_programName.m_name; m_parsedAlias = arg; //preserve the original form -- cgit v1.2.3 From a47f3719a995dc5f5b75d2e384a549b73c229697 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 16 Feb 2012 21:45:14 -0800 Subject: Windows 7 fix: the password prompt doesn't appear until after the password is typed (Erik Costlow). --- src/main/java/com/beust/jcommander/internal/JDK6Console.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/internal/JDK6Console.java b/src/main/java/com/beust/jcommander/internal/JDK6Console.java index f0c60d2..62e2a1e 100644 --- a/src/main/java/com/beust/jcommander/internal/JDK6Console.java +++ b/src/main/java/com/beust/jcommander/internal/JDK6Console.java @@ -27,6 +27,7 @@ public class JDK6Console implements Console { public char[] readPassword() { try { + writer.flush(); Method readPasswordMethod = console.getClass().getDeclaredMethod("readPassword", new Class[0]); return (char[]) readPasswordMethod.invoke(console, new Object[0]); } -- cgit v1.2.3 From a3199885e5e515af41a01c4d693bf96f1dafbd67 Mon Sep 17 00:00:00 2001 From: Adrian Muraru Date: Sat, 25 Feb 2012 04:28:17 +0200 Subject: [Enum Args] If not set, the description of an enum arg is set to the list of options --- src/main/java/com/beust/jcommander/ParameterDescription.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index bf2f3c7..f90c6a5 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -21,6 +21,7 @@ package com.beust.jcommander; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; +import java.util.EnumSet; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -121,7 +122,13 @@ public class ParameterDescription { m_jCommander = jCommander; if (m_parameterAnnotation != null) { - initDescription(m_parameterAnnotation.description(), m_parameterAnnotation.descriptionKey(), + String description; + if (Enum.class.isAssignableFrom(field.getType()) && m_parameterAnnotation.description().isEmpty()) { + description = "Options: " + EnumSet.allOf((Class) field.getType()); + }else { + description = m_parameterAnnotation.description(); + } + initDescription(description, m_parameterAnnotation.descriptionKey(), m_parameterAnnotation.names()); } else if (m_dynamicParameterAnnotation != null) { initDescription(m_dynamicParameterAnnotation.description(), -- cgit v1.2.3 From 39e431ec5e9c2505973a976f62a91e738b85fe4c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 25 Feb 2012 16:43:59 -0800 Subject: Fixed: GITHUB-97: Required password always complains that it is not specified (timoteoponce) --- src/main/java/com/beust/jcommander/JCommander.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index cfa23e1..9d8123a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -601,6 +601,7 @@ public class JCommander { // char[] password = readPassword(pd.getDescription()); pd.addValue(new String(password)); + m_requiredFields.remove(pd.getField()); } else { if (pd.getParameter().variableArity()) { // -- cgit v1.2.3 From ea2ebd84d4ac2c47706c4599f528f5263e199f0b Mon Sep 17 00:00:00 2001 From: evigeant Date: Sun, 26 Feb 2012 16:07:35 -0500 Subject: Fixed indentation on Options in command usage. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9d8123a..e257d22 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -945,7 +945,7 @@ public class JCommander { // // Display all the names and descriptions // - if (sorted.size() > 0) out.append(indent).append("\n Options:\n"); + if (sorted.size() > 0) out.append(indent).append("\n").append(indent).append(" Options:\n"); for (ParameterDescription pd : sorted) { int l = pd.getNames().length(); int spaceCount = longestName - l; -- cgit v1.2.3 From 8ebf58f752ae0703b70af57cecfe584968442558 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 10 Mar 2012 16:12:16 -0800 Subject: Fixed: GITHUB-108: Dynamic parameters with "=" in them are not parsed correctly (szhem) --- src/main/java/com/beust/jcommander/WrappedParameter.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index bba888f..ed7f198 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -54,12 +54,14 @@ public class WrappedParameter { } else { String a = m_dynamicParameter.assignment(); String sv = value.toString(); - String[] kv = sv.split(a); - if (kv.length != 2) { - throw new ParameterException("Dynamic parameter expected a value of the form a" + a + "b" - + " but got:" + sv); + + int aInd = sv.indexOf(a); + if (aInd == -1) { + throw new ParameterException( + "Dynamic parameter expected a value of the form a" + a + "b" + + " but got:" + sv); } - callPut(object, field, kv[0], kv[1]); + callPut(object, field, sv.substring(0, aInd), sv.substring(aInd + 1)); } } -- cgit v1.2.3 From 27e06134bd278f493a78cb7b4cea9be35b9ae7e0 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 12 Mar 2012 12:09:40 -0700 Subject: Fixed Javadoc warnings. --- src/main/java/com/beust/jcommander/IVariableArity.java | 2 +- src/main/java/com/beust/jcommander/converters/IParameterSplitter.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IVariableArity.java b/src/main/java/com/beust/jcommander/IVariableArity.java index e7499c9..e8a40ba 100644 --- a/src/main/java/com/beust/jcommander/IVariableArity.java +++ b/src/main/java/com/beust/jcommander/IVariableArity.java @@ -2,7 +2,7 @@ package com.beust.jcommander; /** * Must be implemented by argument classes that contain at least one - * @Parameter with "variableArity = true". + * \@Parameter with "variableArity = true". */ public interface IVariableArity { diff --git a/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java index e8b87b0..5859f4a 100644 --- a/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java +++ b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java @@ -5,8 +5,6 @@ import java.util.List; /** * Convert a string representing several parameters (e.g. "a,b,c" or "d/e/f") into a * list of arguments ([a,b,c] and [d,e,f]). - * - * @param */ public interface IParameterSplitter { List split(String value); -- cgit v1.2.3 From 3506d0225bc20b569aeb22db93eaa78b20e6571f Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 12 Mar 2012 14:51:40 -0700 Subject: Fixed: GITHUB-105: If no description is given for an enum, use that enum's value (Adrian Muraru) --- src/main/java/com/beust/jcommander/ParameterDescription.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index f90c6a5..4de95d5 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -111,6 +111,7 @@ public class ParameterDescription { } } + @SuppressWarnings("unchecked") private void init(Object object, Field field, ResourceBundle bundle, JCommander jCommander) { m_object = object; @@ -123,7 +124,8 @@ public class ParameterDescription { if (m_parameterAnnotation != null) { String description; - if (Enum.class.isAssignableFrom(field.getType()) && m_parameterAnnotation.description().isEmpty()) { + if (Enum.class.isAssignableFrom(field.getType()) + && m_parameterAnnotation.description().isEmpty()) { description = "Options: " + EnumSet.allOf((Class) field.getType()); }else { description = m_parameterAnnotation.description(); -- cgit v1.2.3 From 59b3e36fa8add6ec52422fc887d98021ab8ae418 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 13 Mar 2012 14:17:20 -0700 Subject: Query all the option names when trying to find a default value for a parameter. --- src/main/java/com/beust/jcommander/JCommander.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index e257d22..3a1b684 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -565,11 +565,13 @@ public class JCommander { } private void initializeDefaultValue(ParameterDescription pd) { - String optionName = pd.getParameter().names()[0]; - String def = m_defaultProvider.getDefaultValueFor(optionName); - if (def != null) { - p("Initializing " + optionName + " with default value:" + def); - pd.addValue(def, true /* default */); + for (String optionName : pd.getParameter().names()) { + String def = m_defaultProvider.getDefaultValueFor(optionName); + if (def != null) { + p("Initializing " + optionName + " with default value:" + def); + pd.addValue(def, true /* default */); + return; + } } } -- cgit v1.2.3 From cc2bd844ba7a6996a334b624b939a4af61e612b3 Mon Sep 17 00:00:00 2001 From: pmendelson Date: Thu, 15 Mar 2012 10:55:17 -0400 Subject: Modified usage function to display a placeholder for parameters that are designed as passwords --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3a1b684..d1c670f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -967,7 +967,7 @@ public class JCommander { } if (def != null && ! "".equals(def)) { out.append("\n" + spaces(indentCount + 1)) - .append("Default: " + def); + .append("Default: " + (parameter.password()?"********":def)); } out.append("\n"); } @@ -1390,3 +1390,4 @@ public class JCommander { } } } + -- cgit v1.2.3 From ca0789ba868746845d31c2ee9e354d8bfbdeca6e Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 18 Apr 2012 10:14:48 -0700 Subject: Fixed: StringIndexOutOfBoundsException if passing an empty parameter (bomanz) --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3a1b684..5899bb8 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -383,7 +383,7 @@ public class JCommander { private boolean isOption(String[] args, String arg) { String prefixes = getOptionPrefixes(args, arg); - return prefixes.indexOf(arg.charAt(0)) >= 0; + return arg.length() > 0 && prefixes.indexOf(arg.charAt(0)) >= 0; } private ParameterDescription getPrefixDescriptionFor(String arg) { -- cgit v1.2.3 From 5414de6562cc1a597c0d522fc4889e0f4136306c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 26 Apr 2012 12:28:11 -0700 Subject: Fixed bug with multiple variable arities. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b9f83d9..97d1eaa 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -609,7 +609,7 @@ public class JCommander { // // Variable arity? // - i = processVariableArity(args, i, pd); + i += processVariableArity(args, i, pd); } else { // // Regular option -- cgit v1.2.3 From 74664b26b3b9cdaec4a683ec9666828cbc856e44 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 26 Apr 2012 12:46:14 -0700 Subject: Better variable arity. --- src/main/java/com/beust/jcommander/JCommander.java | 41 ++++++++++++++++------ 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 97d1eaa..66aec1e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -701,36 +701,55 @@ public class JCommander { return null; } + private class DefaultVariableArity implements IVariableArity { + + public int processVariableArity(String optionName, String[] options) { + int i = 0; + while (i < options.length && !isOption(options, options[i])) { + i++; + } + return i; + } + } + private final IVariableArity DEFAULT_VARIABLE_ARITY = new DefaultVariableArity(); + /** * @return the number of options that were processed. */ private int processVariableArity(String[] args, int index, ParameterDescription pd) { Object arg = pd.getObject(); + IVariableArity va; if (! (arg instanceof IVariableArity)) { - throw new ParameterException("Arg class " + arg.getClass() - + " should implement IVariableArity"); + va = DEFAULT_VARIABLE_ARITY; + } else { + va = (IVariableArity) arg; } - IVariableArity va = (IVariableArity) arg; List currentArgs = Lists.newArrayList(); for (int j = index + 1; j < args.length; j++) { currentArgs.add(args[j]); } - int result = va.processVariableArity(pd.getParameter().names()[0], + int arity = va.processVariableArity(pd.getParameter().names()[0], currentArgs.toArray(new String[0])); - return result; + + return processFixedArity(args, index, pd, List.class, arity); } private int processFixedArity(String[] args, int index, ParameterDescription pd, Class fieldType) { // Regular parameter, use the arity to tell use how many values // we need to consume - String arg = args[index]; int arity = pd.getParameter().arity(); int n = (arity != -1 ? arity : 1); + return processFixedArity(args, index, pd, fieldType, n); + } + + private int processFixedArity(String[] args, int index, ParameterDescription pd, + Class fieldType, int arity) { + String arg = args[index]; // Special case for boolean parameters of arity 0 - if (n == 0 && + if (arity == 0 && (Boolean.class.isAssignableFrom(fieldType) || boolean.class.isAssignableFrom(fieldType))) { pd.addValue("true"); @@ -738,14 +757,14 @@ public class JCommander { } else if (index < args.length - 1) { int offset = "--".equals(args[index + 1]) ? 1 : 0; - if (index + n < args.length) { - for (int j = 1; j <= n; j++) { + if (index + arity < args.length) { + for (int j = 1; j <= arity; j++) { pd.addValue(trim(args[index + j + offset])); m_requiredFields.remove(pd.getField()); } - index += n + offset; + index += arity + offset; } else { - throw new ParameterException("Expected " + n + " values after " + arg); + throw new ParameterException("Expected " + arity + " values after " + arg); } } else { throw new ParameterException("Expected a value after parameter " + arg); -- cgit v1.2.3 From 61e65090c5495518a9a521149dbecbd17e1df193 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 26 Apr 2012 13:58:48 -0700 Subject: Command descriptions (@Parameters(resourceBundle)) were not i18n'ed properly. --- src/main/java/com/beust/jcommander/JCommander.java | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 66aec1e..6b712f7 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -47,6 +47,7 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; @@ -895,9 +896,22 @@ public class JCommander { throw new ParameterException("Asking description for unknown command: " + commandName); } - Parameters p = jc.getObjects().get(0).getClass().getAnnotation(Parameters.class); + Object arg = jc.getObjects().get(0); + Parameters p = arg.getClass().getAnnotation(Parameters.class); String result = jc.getMainParameterDescription(); - if (p != null) result = getI18nString(p.commandDescriptionKey(), p.commandDescription()); + ResourceBundle bundle = null; + if (p != null) { + String bundleName = p.resourceBundle(); + if (!"".equals(bundleName)) { + bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); + } else { + bundle = m_bundle; + } + + if (bundle != null) { + result = getI18nString(bundle, p.commandDescriptionKey(), p.commandDescription()); + } + } return result; } @@ -906,8 +920,8 @@ public class JCommander { * @return The internationalized version of the string if available, otherwise * return def. */ - private String getI18nString(String key, String def) { - String s = m_bundle != null ? m_bundle.getString(key) : null; + private String getI18nString(ResourceBundle bundle, String key, String def) { + String s = bundle != null ? bundle.getString(key) : null; return s != null ? s : def; } -- cgit v1.2.3 From fb38f40b769781cb2cd00763865bc0aef59f392a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 2 May 2012 11:52:39 -0700 Subject: Fixed: bug with several multiple arity parameters (VariableArityTest). --- src/main/java/com/beust/jcommander/JCommander.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 6b712f7..0017bd1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -588,9 +588,10 @@ public class JCommander { while (i < args.length && ! commandParsed) { String arg = args[i]; String a = trim(arg); - p("Parsing arg:" + a); + p("Parsing arg: " + a); JCommander jc = findCommandByAlias(arg); + int increment = 1; if (isOption(args, a) && jc == null) { // // Option @@ -610,7 +611,7 @@ public class JCommander { // // Variable arity? // - i += processVariableArity(args, i, pd); + increment = processVariableArity(args, i, pd); } else { // // Regular option @@ -624,7 +625,7 @@ public class JCommander { pd.addValue("true"); m_requiredFields.remove(pd.getField()); } else { - i = processFixedArity(args, i, pd, fieldType); + increment = processFixedArity(args, i, pd, fieldType); } } } @@ -675,7 +676,7 @@ public class JCommander { } } } - i++; + i += increment; } // Mark the parameter descriptions held in m_fields as assigned @@ -733,7 +734,8 @@ public class JCommander { int arity = va.processVariableArity(pd.getParameter().names()[0], currentArgs.toArray(new String[0])); - return processFixedArity(args, index, pd, List.class, arity); + int result = processFixedArity(args, index, pd, List.class, arity); + return result; } private int processFixedArity(String[] args, int index, ParameterDescription pd, @@ -746,8 +748,9 @@ public class JCommander { return processFixedArity(args, index, pd, fieldType, n); } - private int processFixedArity(String[] args, int index, ParameterDescription pd, + private int processFixedArity(String[] args, int originalIndex, ParameterDescription pd, Class fieldType, int arity) { + int index = originalIndex; String arg = args[index]; // Special case for boolean parameters of arity 0 if (arity == 0 && @@ -771,7 +774,7 @@ public class JCommander { throw new ParameterException("Expected a value after parameter " + arg); } - return index; + return arity + 1; } /** -- cgit v1.2.3 From bb0873edf216718d08386bbff6b6f93aacf72708 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 2 May 2012 11:52:51 -0700 Subject: Don't display no-op validations in debug mode. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 4de95d5..4b77478 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -18,6 +18,8 @@ package com.beust.jcommander; +import com.beust.jcommander.validators.NoValidator; + import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; @@ -277,7 +279,9 @@ public class ParameterDescription { public static void validateParameter(Class validator, String name, String value) { try { - p("Validating parameter:" + name + " value:" + value + " validator:" + validator); + if (validator != NoValidator.class) { + p("Validating parameter:" + name + " value:" + value + " validator:" + validator); + } validator.newInstance().validate(name, value); } catch (InstantiationException e) { throw new ParameterException("Can't instantiate validator:" + e); -- cgit v1.2.3 From 5219e93646ed740bd837e4e6b6033bc4391135ba Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 2 May 2012 11:58:20 -0700 Subject: Merge. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 4b77478..832a25b 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -233,8 +233,7 @@ public class ParameterDescription { + " to parameter:" + m_field.getName()); String name = m_wrappedParameter.names()[0]; if (m_assigned && ! isMultiOption()) { - throw new ParameterException("Can only specify option " + name - + " once."); + throw new ParameterException("Can only specify option " + name + " once."); } validateParameter(name, value); -- cgit v1.2.3 From 13a57cd81965605f1050f20ed2d4169e6d6d24df Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 8 May 2012 15:14:12 -0700 Subject: Fixed: 113: getCommandDescription() returns the description of the main parameter instead of that of the command --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 0017bd1..34e80c4 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -901,9 +901,10 @@ public class JCommander { Object arg = jc.getObjects().get(0); Parameters p = arg.getClass().getAnnotation(Parameters.class); - String result = jc.getMainParameterDescription(); ResourceBundle bundle = null; + String result = null; if (p != null) { + result = p.commandDescription(); String bundleName = p.resourceBundle(); if (!"".equals(bundleName)) { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); -- cgit v1.2.3 From c10f00e203d5e2b035b18382df59864363dfa0cd Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 14 May 2012 10:16:08 -0700 Subject: Better handling of plurals. --- src/main/java/com/beust/jcommander/JCommander.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 34e80c4..1d8a373 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -306,7 +306,9 @@ public class JCommander { for (ParameterDescription pd : m_requiredFields.values()) { missingFields.append(pd.getNames()).append(" "); } - throw new ParameterException("The following options are required: " + missingFields); + throw new ParameterException("The following " + + pluralize(m_requiredFields.size(), "option is required: ", "options are required: ") + + missingFields); } if (m_mainParameterDescription != null) { @@ -318,6 +320,10 @@ public class JCommander { } } + private static String pluralize(int quantity, String singular, String plural) { + return quantity == 1 ? singular : plural; + } + /** * Expand the command line parameters to take @ parameters into account. * When @ is encountered, the content of the file that follows is inserted -- cgit v1.2.3 From 9e22cffb2d22829cb5e2d1bf4d64d87df69d2983 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 15 May 2012 14:49:22 -0700 Subject: Fixed: if using a different option prefix, unknown option are mistakenly reported as "no main parameter defined" (kurmasz) --- src/main/java/com/beust/jcommander/JCommander.java | 22 ++++++++++++++++------ src/main/java/com/beust/jcommander/Strings.java | 7 +++++++ 2 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/Strings.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1d8a373..c56ecce 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -439,8 +439,22 @@ public class JCommander { .getAnnotation(Parameters.class); if (p != null) return p.optionPrefixes(); } + String result = Parameters.DEFAULT_OPTION_PREFIXES; - return Parameters.DEFAULT_OPTION_PREFIXES; + // See if any of the objects contains a @Parameters(optionPrefixes) + StringBuilder sb = new StringBuilder(); + for (Object o : m_objects) { + Parameters p = o.getClass().getAnnotation(Parameters.class); + if (p != null && !Parameters.DEFAULT_OPTION_PREFIXES.equals(p.optionPrefixes())) { + sb.append(p.optionPrefixes()); + } + } + + if (! Strings.isStringEmpty(sb.toString())) { + result = sb.toString(); + } + + return result; } /** @@ -643,7 +657,7 @@ public class JCommander { // // Main parameter // - if (! isStringEmpty(arg)) { + if (! Strings.isStringEmpty(arg)) { if (m_commands.isEmpty()) { // // Regular (non-command) parsing @@ -800,10 +814,6 @@ public class JCommander { return result; } - private static boolean isStringEmpty(String s) { - return s == null || "".equals(s); - } - /** * @return the field that's meant to receive all the parameters that are not options. * diff --git a/src/main/java/com/beust/jcommander/Strings.java b/src/main/java/com/beust/jcommander/Strings.java new file mode 100644 index 0000000..591a38a --- /dev/null +++ b/src/main/java/com/beust/jcommander/Strings.java @@ -0,0 +1,7 @@ +package com.beust.jcommander; + +public class Strings { + public static boolean isStringEmpty(String s) { + return s == null || "".equals(s); + } +} -- cgit v1.2.3 From 5bbf7af0a020eb6da94be078c80300c19b6d77d4 Mon Sep 17 00:00:00 2001 From: Jason Wheeler Date: Tue, 29 May 2012 13:48:17 -0600 Subject: added echoInput parameter to @Parameter annotation to control whether characters are hidden when entering passwords (only works in Java 6 when password == true) --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++--- src/main/java/com/beust/jcommander/Parameter.java | 6 ++++++ src/main/java/com/beust/jcommander/WrappedParameter.java | 4 ++++ src/main/java/com/beust/jcommander/internal/Console.java | 2 +- .../java/com/beust/jcommander/internal/DefaultConsole.java | 2 +- .../java/com/beust/jcommander/internal/JDK6Console.java | 14 ++++++++++---- 6 files changed, 25 insertions(+), 9 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index c56ecce..61eeae8 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -623,7 +623,7 @@ public class JCommander { // // Password option, use the Console to retrieve the password // - char[] password = readPassword(pd.getDescription()); + char[] password = readPassword(pd.getDescription(), pd.getParameter().echoInput()); pd.addValue(new String(password)); m_requiredFields.remove(pd.getField()); } else { @@ -801,9 +801,9 @@ public class JCommander { * Invoke Console.readPassword through reflection to avoid depending * on Java 6. */ - private char[] readPassword(String description) { + private char[] readPassword(String description, boolean echoInput) { getConsole().print(description + ": "); - return getConsole().readPassword(); + return getConsole().readPassword(echoInput); } private String[] subArray(String[] args, int index) { diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 1b2a00f..0d19dc4 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -100,4 +100,10 @@ public @interface Parameter { * a comma separated splitter will be used. */ Class splitter() default CommaParameterSplitter.class; + + /** + * If true, console will not echo typed input + * Used in conjunction with password = true + */ + boolean echoInput() default false; } diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index ed7f198..991f132 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -46,6 +46,10 @@ public class WrappedParameter { public Class validateWith() { return m_parameter != null ? m_parameter.validateWith() : m_dynamicParameter.validateWith(); } + + public boolean echoInput() { + return m_parameter != null ? m_parameter.echoInput() : false; + } public void addValue(Field field, Object object, Object value) throws IllegalArgumentException, IllegalAccessException { diff --git a/src/main/java/com/beust/jcommander/internal/Console.java b/src/main/java/com/beust/jcommander/internal/Console.java index e2bddb3..95eafe1 100644 --- a/src/main/java/com/beust/jcommander/internal/Console.java +++ b/src/main/java/com/beust/jcommander/internal/Console.java @@ -6,5 +6,5 @@ public interface Console { void println(String msg); - char[] readPassword(); + char[] readPassword(boolean echoInput); } diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java index b838610..65e87ba 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java @@ -16,7 +16,7 @@ public class DefaultConsole implements Console { System.out.println(msg); } - public char[] readPassword() { + public char[] readPassword(boolean echoInput) { try { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader in = new BufferedReader(isr); diff --git a/src/main/java/com/beust/jcommander/internal/JDK6Console.java b/src/main/java/com/beust/jcommander/internal/JDK6Console.java index 62e2a1e..70cb186 100644 --- a/src/main/java/com/beust/jcommander/internal/JDK6Console.java +++ b/src/main/java/com/beust/jcommander/internal/JDK6Console.java @@ -25,15 +25,21 @@ public class JDK6Console implements Console { writer.println(msg); } - public char[] readPassword() { + public char[] readPassword(boolean echoInput) { try { writer.flush(); - Method readPasswordMethod = console.getClass().getDeclaredMethod("readPassword", new Class[0]); - return (char[]) readPasswordMethod.invoke(console, new Object[0]); + Method method; + if (echoInput) { + method = console.getClass().getDeclaredMethod("readLine", new Class[0]); + return ((String) method.invoke(console, new Object[0])).toCharArray(); + } else { + method = console.getClass().getDeclaredMethod("readPassword", new Class[0]); + return (char[]) method.invoke(console, new Object[0]); + } } catch (Exception e) { throw new ParameterException(e); } } -} +} \ No newline at end of file -- cgit v1.2.3 From 074b8af3781fbc976f01b43bc3fa0d8ef0431599 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 31 May 2012 11:51:19 -0700 Subject: Fixed: wasn't handling parameters that start with " but don't end with one correctly --- src/main/java/com/beust/jcommander/JCommander.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 61eeae8..dd758ef 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -492,11 +492,8 @@ public class JCommander { */ private static String trim(String string) { String result = string.trim(); - if (result.startsWith("\"")) { - if (result.endsWith("\"")) { - return result.substring(1, result.length() - 1); - } - return result.substring(1); + if (result.startsWith("\"") && result.endsWith("\"")) { + result = result.substring(1, result.length() - 1); } return result; } -- cgit v1.2.3 From e903207930001edf324f2623b763df0f75e82a3c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 10 Jun 2012 18:47:55 -0700 Subject: Added: IValueValidator to validate parameter values (typed) as oppoed to IParameterValidator which validates strings --- .../com/beust/jcommander/DynamicParameter.java | 3 ++ .../java/com/beust/jcommander/IValueValidator.java | 14 +++++++++ src/main/java/com/beust/jcommander/Parameter.java | 9 +++++- .../com/beust/jcommander/ParameterDescription.java | 25 +++++++++++++++- .../com/beust/jcommander/WrappedParameter.java | 9 +++++- .../jcommander/validators/NoValueValidator.java | 35 ++++++++++++++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IValueValidator.java create mode 100644 src/main/java/com/beust/jcommander/validators/NoValueValidator.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java index 77b8632..2159c1f 100644 --- a/src/main/java/com/beust/jcommander/DynamicParameter.java +++ b/src/main/java/com/beust/jcommander/DynamicParameter.java @@ -3,6 +3,7 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; import com.beust.jcommander.validators.NoValidator; +import com.beust.jcommander.validators.NoValueValidator; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -44,4 +45,6 @@ public @interface DynamicParameter { * The character(s) used to assign the values. */ String assignment() default "="; + + Class validateValueWith() default NoValueValidator.class; } diff --git a/src/main/java/com/beust/jcommander/IValueValidator.java b/src/main/java/com/beust/jcommander/IValueValidator.java new file mode 100644 index 0000000..feed25d --- /dev/null +++ b/src/main/java/com/beust/jcommander/IValueValidator.java @@ -0,0 +1,14 @@ +package com.beust.jcommander; + +public interface IValueValidator { + /** + * Validate the parameter. + * + * @param name The name of the parameter (e.g. "-host"). + * @param value The value of the parameter that we need to validate + * + * @throws ParameterException Thrown if the value of the parameter is invalid. + */ + void validate(String name, T value) throws ParameterException; + +} diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 0d19dc4..c73d69b 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -24,6 +24,7 @@ import com.beust.jcommander.converters.CommaParameterSplitter; import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.validators.NoValidator; +import com.beust.jcommander.validators.NoValueValidator; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -86,10 +87,15 @@ public @interface Parameter { boolean hidden() default false; /** - * The validation class to use. + * Validate the parameter found on the command line. */ Class validateWith() default NoValidator.class; + /** + * Validate the value for this parameter. + */ + Class validateValueWith() default NoValueValidator.class; + /** * @return true if this parameter has a variable arity. See @{IVariableArity} */ @@ -106,4 +112,5 @@ public @interface Parameter { * Used in conjunction with password = true */ boolean echoInput() default false; + } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 832a25b..9299e59 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -19,6 +19,7 @@ package com.beust.jcommander; import com.beust.jcommander.validators.NoValidator; +import com.beust.jcommander.validators.NoValueValidator; import java.lang.reflect.Field; import java.util.ArrayList; @@ -159,7 +160,7 @@ public class ParameterDescription { private void validateDefaultValues(String[] names) { String name = names.length > 0 ? names[0] : ""; - validateParameter(name, m_default.toString()); + validateValueParameter(name, m_default); } public String getLongestName() { @@ -241,6 +242,7 @@ public class ParameterDescription { Class type = m_field.getType(); Object convertedValue = m_jCommander.convertValue(this, value); + validateValueParameter(name, convertedValue); boolean isCollection = Collection.class.isAssignableFrom(type); try { @@ -275,6 +277,27 @@ public class ParameterDescription { } } + private void validateValueParameter(String name, Object value) { + Class validator = m_wrappedParameter.validateValueWith(); + if (validator != null) { + validateValueParameter(validator, name, value); + } + } + + public static void validateValueParameter(Class validator, + String name, Object value) { + try { + if (validator != NoValueValidator.class) { + p("Validating value parameter:" + name + " value:" + value + " validator:" + validator); + } + validator.newInstance().validate(name, value); + } catch (InstantiationException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } catch (IllegalAccessException e) { + throw new ParameterException("Can't instantiate validator:" + e); + } + } + public static void validateParameter(Class validator, String name, String value) { try { diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index 991f132..d49205d 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -46,7 +46,13 @@ public class WrappedParameter { public Class validateWith() { return m_parameter != null ? m_parameter.validateWith() : m_dynamicParameter.validateWith(); } - + + public Class validateValueWith() { + return m_parameter != null + ? m_parameter.validateValueWith() + : m_dynamicParameter.validateValueWith(); + } + public boolean echoInput() { return m_parameter != null ? m_parameter.echoInput() : false; } @@ -92,4 +98,5 @@ public class WrappedParameter { public String getAssignment() { return m_dynamicParameter != null ? m_dynamicParameter.assignment() : ""; } + } diff --git a/src/main/java/com/beust/jcommander/validators/NoValueValidator.java b/src/main/java/com/beust/jcommander/validators/NoValueValidator.java new file mode 100644 index 0000000..21fa820 --- /dev/null +++ b/src/main/java/com/beust/jcommander/validators/NoValueValidator.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2011 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.validators; + +import com.beust.jcommander.IValueValidator; +import com.beust.jcommander.ParameterException; + +/** + * This is the default value of the validateValueWith attribute. + * + * @author Cedric Beust + */ +public class NoValueValidator implements IValueValidator { + + public void validate(String parameterName, T parameterValue) + throws ParameterException { + } + +} -- cgit v1.2.3 From 369d387138b6da9e77e01d82273ef6271580eb47 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 24 Jun 2012 15:12:31 -0700 Subject: Support for setters on top of fields. --- src/main/java/com/beust/jcommander/JCommander.java | 279 ++++++++++++--------- src/main/java/com/beust/jcommander/Parameter.java | 3 +- .../com/beust/jcommander/ParameterDescription.java | 81 +++--- .../java/com/beust/jcommander/Parameterized.java | 224 +++++++++++++++++ .../com/beust/jcommander/WrappedParameter.java | 22 +- 5 files changed, 438 insertions(+), 171 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/Parameterized.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index dd758ef..66ce5f5 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -31,16 +31,13 @@ import com.beust.jcommander.internal.Maps; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; -import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; @@ -79,10 +76,10 @@ public class JCommander { private List m_objects = Lists.newArrayList(); /** - * This field will contain whatever command line parameter is not an option. + * This field/method will contain whatever command line parameter is not an option. * It is expected to be a List. */ - private Field m_mainParameterField = null; + private Parameterized m_mainParameter = null; /** * The object on which we found the main parameter field. @@ -97,19 +94,19 @@ public class JCommander { private ParameterDescription m_mainParameterDescription; /** - * A set of all the fields that are required. During the reflection phase, + * A set of all the parameterizeds that are required. During the reflection phase, * this field receives all the fields that are annotated with required=true * and during the parsing phase, all the fields that are assigned a value * are removed from it. At the end of the parsing phase, if it's not empty, * then some required fields did not receive a value and an exception is * thrown. */ - private Map m_requiredFields = Maps.newHashMap(); + private Map m_requiredFields = Maps.newHashMap(); /** - * A map of all the annotated fields. + * A map of all the parameterized fields/methods/ */ - private Map m_fields = Maps.newHashMap(); + private Map m_fields = Maps.newHashMap(); private ResourceBundle m_bundle; @@ -142,6 +139,7 @@ public class JCommander { private Comparator m_parameterDescriptionComparator = new Comparator() { + @Override public int compare(ParameterDescription p0, ParameterDescription p1) { return p0.getLongestName().compareTo(p1.getLongestName()); } @@ -512,74 +510,138 @@ public class JCommander { private void addDescription(Object object) { Class cls = object.getClass(); - while (!Object.class.equals(cls)) { - for (Field f : cls.getDeclaredFields()) { - p("Field:" + cls.getSimpleName() + "." + f.getName()); - f.setAccessible(true); - Annotation annotation = f.getAnnotation(Parameter.class); - Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class); - Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class); - if (annotation != null) { - // - // @Parameter - // - Parameter p = (Parameter) annotation; - if (p.names().length == 0) { - p("Found main parameter:" + f); - if (m_mainParameterField != null) { - throw new ParameterException("Only one @Parameter with no names attribute is" - + " allowed, found:" + m_mainParameterField + " and " + f); - } - m_mainParameterField = f; - m_mainParameterObject = object; - m_mainParameterAnnotation = p; - m_mainParameterDescription = new ParameterDescription(object, p, f, m_bundle, this); - } else { - for (String name : p.names()) { - if (m_descriptions.containsKey(name)) { - throw new ParameterException("Found the option " + name + " multiple times"); - } - p("Adding description for " + name); - ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle, this); - m_fields.put(f, pd); - m_descriptions.put(name, pd); - - if (p.required()) m_requiredFields.put(f, pd); - } - } - } else if (delegateAnnotation != null) { - // - // @ParametersDelegate - // - try { - Object delegateObject = f.get(object); - if (delegateObject == null){ - throw new ParameterException("Delegate field '" + f.getName() + "' cannot be null."); - } - addDescription(delegateObject); - } catch (IllegalAccessException e) { + List parameterizeds = Parameterized.parseArg(object); + for (Parameterized parameterized : parameterizeds) { + WrappedParameter wp = parameterized.getWrappedParameter(); + if (wp != null && wp.getParameter() != null) { + Parameter annotation = wp.getParameter(); + // + // @Parameter + // + Parameter p = annotation; + if (p.names().length == 0) { + p("Found main parameter:" + parameterized); + if (m_mainParameter != null) { + throw new ParameterException("Only one @Parameter with no names attribute is" + + " allowed, found:" + m_mainParameter + " and " + parameterized); } - } else if (dynamicParameter != null) { - // - // @DynamicParameter - // - DynamicParameter dp = (DynamicParameter) dynamicParameter; - for (String name : dp.names()) { + m_mainParameter = parameterized; + m_mainParameterObject = object; + m_mainParameterAnnotation = p; + m_mainParameterDescription = + new ParameterDescription(object, p, parameterized, m_bundle, this); + } else { + for (String name : p.names()) { if (m_descriptions.containsKey(name)) { throw new ParameterException("Found the option " + name + " multiple times"); } p("Adding description for " + name); - ParameterDescription pd = new ParameterDescription(object, dp, f, m_bundle, this); - m_fields.put(f, pd); + ParameterDescription pd = + new ParameterDescription(object, p, parameterized, m_bundle, this); + m_fields.put(parameterized, pd); m_descriptions.put(name, pd); - if (dp.required()) m_requiredFields.put(f, pd); + if (p.required()) m_requiredFields.put(parameterized, pd); } } + } else if (parameterized.getDelegateAnnotation() != null) { + // + // @ParametersDelegate + // + Object delegateObject = parameterized.get(object); + if (delegateObject == null){ + throw new ParameterException("Delegate field '" + parameterized.getName() + + "' cannot be null."); + } + addDescription(delegateObject); + } else if (wp != null && wp.getDynamicParameter() != null) { + // + // @DynamicParameter + // + DynamicParameter dp = wp.getDynamicParameter(); + for (String name : dp.names()) { + if (m_descriptions.containsKey(name)) { + throw new ParameterException("Found the option " + name + " multiple times"); + } + p("Adding description for " + name); + ParameterDescription pd = + new ParameterDescription(object, dp, parameterized, m_bundle, this); + m_fields.put(parameterized, pd); + m_descriptions.put(name, pd); + + if (dp.required()) m_requiredFields.put(parameterized, pd); + } } - // Traverse the super class until we find Object.class - cls = cls.getSuperclass(); } + +// while (!Object.class.equals(cls)) { +// for (Field f : cls.getDeclaredFields()) { +// p("Field:" + cls.getSimpleName() + "." + f.getName()); +// f.setAccessible(true); +// Annotation annotation = f.getAnnotation(Parameter.class); +// Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class); +// Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class); +// if (annotation != null) { +// // +// // @Parameter +// // +// Parameter p = (Parameter) annotation; +// if (p.names().length == 0) { +// p("Found main parameter:" + f); +// if (m_mainParameterField != null) { +// throw new ParameterException("Only one @Parameter with no names attribute is" +// + " allowed, found:" + m_mainParameterField + " and " + f); +// } +// m_mainParameterField = parameterized; +// m_mainParameterObject = object; +// m_mainParameterAnnotation = p; +// m_mainParameterDescription = new ParameterDescription(object, p, f, m_bundle, this); +// } else { +// for (String name : p.names()) { +// if (m_descriptions.containsKey(name)) { +// throw new ParameterException("Found the option " + name + " multiple times"); +// } +// p("Adding description for " + name); +// ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle, this); +// m_fields.put(f, pd); +// m_descriptions.put(name, pd); +// +// if (p.required()) m_requiredFields.put(f, pd); +// } +// } +// } else if (delegateAnnotation != null) { +// // +// // @ParametersDelegate +// // +// try { +// Object delegateObject = f.get(object); +// if (delegateObject == null){ +// throw new ParameterException("Delegate field '" + f.getName() + "' cannot be null."); +// } +// addDescription(delegateObject); +// } catch (IllegalAccessException e) { +// } +// } else if (dynamicParameter != null) { +// // +// // @DynamicParameter +// // +// DynamicParameter dp = (DynamicParameter) dynamicParameter; +// for (String name : dp.names()) { +// if (m_descriptions.containsKey(name)) { +// throw new ParameterException("Found the option " + name + " multiple times"); +// } +// p("Adding description for " + name); +// ParameterDescription pd = new ParameterDescription(object, dp, f, m_bundle, this); +// m_fields.put(f, pd); +// m_descriptions.put(name, pd); +// +// if (dp.required()) m_requiredFields.put(f, pd); +// } +// } +// } +// // Traverse the super class until we find Object.class +// cls = cls.getSuperclass(); +// } } private void initializeDefaultValue(ParameterDescription pd) { @@ -622,7 +684,7 @@ public class JCommander { // char[] password = readPassword(pd.getDescription(), pd.getParameter().echoInput()); pd.addValue(new String(password)); - m_requiredFields.remove(pd.getField()); + m_requiredFields.remove(pd.getParameterized()); } else { if (pd.getParameter().variableArity()) { // @@ -633,14 +695,14 @@ public class JCommander { // // Regular option // - Class fieldType = pd.getField().getType(); + Class fieldType = pd.getParameterized().getType(); // Boolean, set to true as soon as we see it, unless it specified // an arity of 1, in which case we need to read the next value if ((fieldType == boolean.class || fieldType == Boolean.class) && pd.getParameter().arity() == -1) { pd.addValue("true"); - m_requiredFields.remove(pd.getField()); + m_requiredFields.remove(pd.getParameterized()); } else { increment = processFixedArity(args, i, pd, fieldType); } @@ -663,11 +725,11 @@ public class JCommander { String value = arg; Object convertedValue = value; - if (m_mainParameterField.getGenericType() instanceof ParameterizedType) { - ParameterizedType p = (ParameterizedType) m_mainParameterField.getGenericType(); + if (m_mainParameter.getGenericType() instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) m_mainParameter.getGenericType(); Type cls = p.getActualTypeArguments()[0]; if (cls instanceof Class) { - convertedValue = convertValue(m_mainParameterField, (Class) cls, value); + convertedValue = convertValue(m_mainParameter, (Class) cls, value); } } @@ -699,29 +761,15 @@ public class JCommander { // Mark the parameter descriptions held in m_fields as assigned for (ParameterDescription parameterDescription : m_descriptions.values()) { if (parameterDescription.isAssigned()) { - m_fields.get(parameterDescription.getField()).setAssigned(true); + m_fields.get(parameterDescription.getParameterized()).setAssigned(true); } } } - /** - * @return the generic type of the collection for this field, or null if not applicable. - */ - private Type findFieldGenericType(Field field) { - if (field.getGenericType() instanceof ParameterizedType) { - ParameterizedType p = (ParameterizedType) field.getGenericType(); - Type cls = p.getActualTypeArguments()[0]; - if (cls instanceof Class) { - return cls; - } - } - - return null; - } - private class DefaultVariableArity implements IVariableArity { + @Override public int processVariableArity(String optionName, String[] options) { int i = 0; while (i < options.length && !isOption(options, options[i])) { @@ -774,14 +822,14 @@ public class JCommander { (Boolean.class.isAssignableFrom(fieldType) || boolean.class.isAssignableFrom(fieldType))) { pd.addValue("true"); - m_requiredFields.remove(pd.getField()); + m_requiredFields.remove(pd.getParameterized()); } else if (index < args.length - 1) { int offset = "--".equals(args[index + 1]) ? 1 : 0; if (index + arity < args.length) { for (int j = 1; j <= arity; j++) { pd.addValue(trim(args[index + j + offset])); - m_requiredFields.remove(pd.getField()); + m_requiredFields.remove(pd.getParameterized()); } index += arity + offset; } else { @@ -818,26 +866,21 @@ public class JCommander { * error message). */ private List getMainParameter(String arg) { - if (m_mainParameterField == null) { + if (m_mainParameter == null) { throw new ParameterException( "Was passed main parameter '" + arg + "' but no main parameter was defined"); } - try { - List result = (List) m_mainParameterField.get(m_mainParameterObject); - if (result == null) { - result = Lists.newArrayList(); - if (! List.class.isAssignableFrom(m_mainParameterField.getType())) { - throw new ParameterException("Main parameter field " + m_mainParameterField - + " needs to be of type List, not " + m_mainParameterField.getType()); - } - m_mainParameterField.set(m_mainParameterObject, result); + List result = (List) m_mainParameter.get(m_mainParameterObject); + if (result == null) { + result = Lists.newArrayList(); + if (! List.class.isAssignableFrom(m_mainParameter.getType())) { + throw new ParameterException("Main parameter field " + m_mainParameter + + " needs to be of type List, not " + m_mainParameter.getType()); } - return result; - } - catch(IllegalAccessException ex) { - throw new ParameterException("Couldn't access main parameter: " + ex.getMessage()); + m_mainParameter.set(m_mainParameterObject, result); } + return result; } public String getMainParameterDescription() { @@ -846,15 +889,15 @@ public class JCommander { : null; } - private int longestName(Collection objects) { - int result = 0; - for (Object o : objects) { - int l = o.toString().length(); - if (l > result) result = l; - } - - return result; - } +// private int longestName(Collection objects) { +// int result = 0; +// for (Object o : objects) { +// int l = o.toString().length(); +// if (l > result) result = l; +// } +// +// return result; +// } /** * Set the program name (used only in the usage). @@ -1128,7 +1171,7 @@ public class JCommander { } public Object convertValue(ParameterDescription pd, String value) { - return convertValue(pd.getField(), pd.getField().getType(), value); + return convertValue(pd.getParameterized(), pd.getParameterized().getType(), value); } /** @@ -1136,8 +1179,8 @@ public class JCommander { * @param type The type of the actual parameter * @param value The value to convert */ - public Object convertValue(Field field, Class type, String value) { - Parameter annotation = field.getAnnotation(Parameter.class); + public Object convertValue(Parameterized parameterized, Class type, String value) { + Parameter annotation = parameterized.getParameter(); // Do nothing if it's a @DynamicParameter if (annotation == null) return value; @@ -1158,7 +1201,7 @@ public class JCommander { } if (converterClass == null) { - Type elementType = findFieldGenericType(field); + Type elementType = parameterized.findFieldGenericType(); converterClass = elementType != null ? findConverter((Class>) elementType) : StringConverter.class; @@ -1194,7 +1237,7 @@ public class JCommander { } else { converter = instantiateConverter(optionName, converterClass); if (type.isAssignableFrom(List.class) - && field.getGenericType() instanceof ParameterizedType) { + && parameterized.getGenericType() instanceof ParameterizedType) { // The field is a List if (listConverterWasSpecified) { diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index c73d69b..51b941f 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -19,6 +19,7 @@ package com.beust.jcommander; import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; import com.beust.jcommander.converters.CommaParameterSplitter; import com.beust.jcommander.converters.IParameterSplitter; @@ -30,7 +31,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) -@Target({ FIELD }) +@Target({ FIELD, METHOD }) public @interface Parameter { /** diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 9299e59..5f4a0a7 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -21,7 +21,6 @@ package com.beust.jcommander; import com.beust.jcommander.validators.NoValidator; import com.beust.jcommander.validators.NoValueValidator; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; @@ -42,7 +41,8 @@ public class ParameterDescription { private Parameter m_parameterAnnotation; private DynamicParameter m_dynamicParameterAnnotation; - private Field m_field; + /** The field/method */ + private Parameterized m_parameterized; /** Keep track of whether a value was added to flag an error */ private boolean m_assigned = false; private ResourceBundle m_bundle; @@ -52,23 +52,25 @@ public class ParameterDescription { /** Longest of the names(), used to present usage() alphabetically */ private String m_longestName = ""; - public ParameterDescription(Object object, DynamicParameter annotation, Field field, + public ParameterDescription(Object object, DynamicParameter annotation, + Parameterized parameterized, ResourceBundle bundle, JCommander jc) { - if (! Map.class.isAssignableFrom(field.getType())) { - throw new ParameterException("@DynamicParameter " + field.getName() + " should be of type " - + "Map but is " + field.getType().getName()); + if (! Map.class.isAssignableFrom(parameterized.getType())) { + throw new ParameterException("@DynamicParameter " + parameterized.getName() + + " should be of type " + + "Map but is " + parameterized.getType().getName()); } m_dynamicParameterAnnotation = annotation; m_wrappedParameter = new WrappedParameter(m_dynamicParameterAnnotation); - init(object, field, bundle, jc); + init(object, parameterized, bundle, jc); } - public ParameterDescription(Object object, Parameter annotation, Field field, + public ParameterDescription(Object object, Parameter annotation, Parameterized parameterized, ResourceBundle bundle, JCommander jc) { m_parameterAnnotation = annotation; m_wrappedParameter = new WrappedParameter(m_parameterAnnotation); - init(object, field, bundle, jc); + init(object, parameterized, bundle, jc); } /** @@ -115,10 +117,10 @@ public class ParameterDescription { } @SuppressWarnings("unchecked") - private void init(Object object, Field field, ResourceBundle bundle, + private void init(Object object, Parameterized parameterized, ResourceBundle bundle, JCommander jCommander) { m_object = object; - m_field = field; + m_parameterized = parameterized; m_bundle = bundle; if (m_bundle == null) { m_bundle = findResourceBundle(object); @@ -127,9 +129,9 @@ public class ParameterDescription { if (m_parameterAnnotation != null) { String description; - if (Enum.class.isAssignableFrom(field.getType()) + if (Enum.class.isAssignableFrom(parameterized.getType()) && m_parameterAnnotation.description().isEmpty()) { - description = "Options: " + EnumSet.allOf((Class) field.getType()); + description = "Options: " + EnumSet.allOf((Class) parameterized.getType()); }else { description = m_parameterAnnotation.description(); } @@ -144,7 +146,7 @@ public class ParameterDescription { } try { - m_default = m_field.get(m_object); + m_default = parameterized.get(object); } catch (Exception e) { } @@ -194,18 +196,14 @@ public class ParameterDescription { return m_wrappedParameter; } - public Field getField() { - return m_field; + public Parameterized getParameterized() { + return m_parameterized; } private boolean isMultiOption() { - Class fieldType = m_field.getType(); + Class fieldType = m_parameterized.getType(); return fieldType.equals(List.class) || fieldType.equals(Set.class) - || isDynamicParameter(m_field); - } - - private boolean isDynamicParameter(Field field) { - return field.getAnnotation(DynamicParameter.class) != null; + || m_parameterized.isDynamicParameter(); } public void addValue(String value) { @@ -231,7 +229,7 @@ public class ParameterDescription { */ public void addValue(String value, boolean isDefault) { p("Adding " + (isDefault ? "default " : "") + "value:" + value - + " to parameter:" + m_field.getName()); + + " to parameter:" + m_parameterized.getName()); String name = m_wrappedParameter.names()[0]; if (m_assigned && ! isMultiOption()) { throw new ParameterException("Can only specify option " + name + " once."); @@ -239,35 +237,30 @@ public class ParameterDescription { validateParameter(name, value); - Class type = m_field.getType(); + Class type = m_parameterized.getType(); Object convertedValue = m_jCommander.convertValue(this, value); validateValueParameter(name, convertedValue); boolean isCollection = Collection.class.isAssignableFrom(type); - try { - if (isCollection) { - @SuppressWarnings("unchecked") - Collection l = (Collection) m_field.get(m_object); - if (l == null || fieldIsSetForTheFirstTime(isDefault)) { - l = newCollection(type); - m_field.set(m_object, l); - } - if (convertedValue instanceof Collection) { - l.addAll((Collection) convertedValue); - } else { // if (isMainParameter || m_parameterAnnotation.arity() > 1) { - l.add(convertedValue); + if (isCollection) { + @SuppressWarnings("unchecked") + Collection l = (Collection) m_parameterized.get(m_object); + if (l == null || fieldIsSetForTheFirstTime(isDefault)) { + l = newCollection(type); + m_parameterized.set(m_object, l); + } + if (convertedValue instanceof Collection) { + l.addAll((Collection) convertedValue); + } else { // if (isMainParameter || m_parameterAnnotation.arity() > 1) { + l.add(convertedValue); // } else { // l. - } - } else { - m_wrappedParameter.addValue(m_field, m_object, convertedValue); } - if (! isDefault) m_assigned = true; - } - catch(IllegalAccessException ex) { - ex.printStackTrace(); + } else { + m_wrappedParameter.addValue(m_parameterized, m_object, convertedValue); } + if (! isDefault) m_assigned = true; } private void validateParameter(String name, String value) { @@ -346,7 +339,7 @@ public class ParameterDescription { @Override public String toString() { - return "[ParameterDescription " + m_field.getName() + "]"; + return "[ParameterDescription " + m_parameterized.getName() + "]"; } public boolean isDynamicParameter() { diff --git a/src/main/java/com/beust/jcommander/Parameterized.java b/src/main/java/com/beust/jcommander/Parameterized.java new file mode 100644 index 0000000..ec698fa --- /dev/null +++ b/src/main/java/com/beust/jcommander/Parameterized.java @@ -0,0 +1,224 @@ +package com.beust.jcommander; + +import com.beust.jcommander.internal.Lists; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; + +/** + * Encapsulate a field or a method annotated with @Parameter or @DynamicParameter + */ +public class Parameterized { + + // Either a method or a field + private Field m_field; + private Method m_method; + private Method m_getter; + + // Either of these two + private WrappedParameter m_wrappedParameter; + private ParametersDelegate m_parametersDelegate; + + public Parameterized(WrappedParameter wp, ParametersDelegate pd, + Field field, Method method) { + m_wrappedParameter = wp; + m_method = method; + m_field = field; + if (m_field != null) { + m_field.setAccessible(true); + } + m_parametersDelegate = pd; + } + + public static List parseArg(Object arg) { + List result = Lists.newArrayList(); + + Class cls = arg.getClass(); + while (!Object.class.equals(cls)) { + for (Field f : cls.getDeclaredFields()) { + Annotation annotation = f.getAnnotation(Parameter.class); + Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class); + Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class); + if (annotation != null) { + result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null, + f, null)); + } else if (dynamicParameter != null) { + result.add(new Parameterized(new WrappedParameter((DynamicParameter) dynamicParameter), null, + f, null)); + } else if (delegateAnnotation != null) { + result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation, + f, null)); + } + } + cls = cls.getSuperclass(); + } + + // Reassigning + cls = arg.getClass(); + while (!Object.class.equals(cls)) { + for (Method m : cls.getDeclaredMethods()) { + Annotation annotation = m.getAnnotation(Parameter.class); + Annotation delegateAnnotation = m.getAnnotation(ParametersDelegate.class); + Annotation dynamicParameter = m.getAnnotation(DynamicParameter.class); + if (annotation != null) { + result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null, + null, m)); + } else if (dynamicParameter != null) { + result.add(new Parameterized(new WrappedParameter((DynamicParameter) annotation), null, + null, m)); + } else if (delegateAnnotation != null) { + result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation, + null, m)); + } + } + cls = cls.getSuperclass(); + } + + return result; + } + + public WrappedParameter getWrappedParameter() { + return m_wrappedParameter; + } + + public Class getType() { + if (m_method != null) { + return m_method.getParameterTypes()[0]; + } else { + return m_field.getType(); + } + } + + public String getName() { + if (m_method != null) { + return m_method.getName(); + } else { + return m_field.getName(); + } + } + + public Object get(Object object) { + try { + if (m_method != null) { + if (m_getter == null) { + m_getter = m_method.getDeclaringClass() + .getMethod("g" + m_method.getName().substring(1), + new Class[0]); + } + return m_getter.invoke(object); + } else { + return m_field.get(object); + } + } catch (SecurityException e) { + throw new ParameterException(e); + } catch (NoSuchMethodException e) { + throw new ParameterException(e); + } catch (IllegalArgumentException e) { + throw new ParameterException(e); + } catch (IllegalAccessException e) { + throw new ParameterException(e); + } catch (InvocationTargetException e) { + throw new ParameterException(e); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((m_field == null) ? 0 : m_field.hashCode()); + result = prime * result + ((m_method == null) ? 0 : m_method.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Parameterized other = (Parameterized) obj; + if (m_field == null) { + if (other.m_field != null) + return false; + } else if (!m_field.equals(other.m_field)) + return false; + if (m_method == null) { + if (other.m_method != null) + return false; + } else if (!m_method.equals(other.m_method)) + return false; + return true; + } + + public boolean isDynamicParameter(Field field) { + if (m_method != null) { + return m_method.getAnnotation(DynamicParameter.class) != null; + } else { + return m_field.getAnnotation(DynamicParameter.class) != null; + } + } + + public void set(Object object, Object value) { + try { + if (m_method != null) { + m_method.invoke(object, value); + } else { + m_field.set(object, value); + } + } catch (IllegalArgumentException ex) { + throw new ParameterException(ex); + } catch (IllegalAccessException ex) { + throw new ParameterException(ex); + } catch (InvocationTargetException ex) { + throw new ParameterException(ex); + } + } + + public ParametersDelegate getDelegateAnnotation() { + return m_parametersDelegate; + } + + public Type getGenericType() { + if (m_method != null) { + return m_method.getGenericParameterTypes()[0]; + } else { + return m_field.getGenericType(); + } + } + + public Parameter getParameter() { + return m_wrappedParameter.getParameter(); + } + + /** + * @return the generic type of the collection for this field, or null if not applicable. + */ + public Type findFieldGenericType() { + if (m_method != null) { + return null; + } else { + if (m_field.getGenericType() instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType) m_field.getGenericType(); + Type cls = p.getActualTypeArguments()[0]; + if (cls instanceof Class) { + return cls; + } + } + } + + return null; + } + + public boolean isDynamicParameter() { + return m_wrappedParameter.getDynamicParameter() != null; + } + +} diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index d49205d..1f690a0 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -1,6 +1,5 @@ package com.beust.jcommander; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -19,6 +18,14 @@ public class WrappedParameter { m_dynamicParameter = p; } + public Parameter getParameter() { + return m_parameter; + } + + public DynamicParameter getDynamicParameter() { + return m_dynamicParameter; + } + public int arity() { return m_parameter != null ? m_parameter.arity() : 1; } @@ -57,10 +64,9 @@ public class WrappedParameter { return m_parameter != null ? m_parameter.echoInput() : false; } - public void addValue(Field field, Object object, Object value) - throws IllegalArgumentException, IllegalAccessException { + public void addValue(Parameterized parameterized, Object object, Object value) { if (m_parameter != null) { - field.set(object, value); + parameterized.set(object, value); } else { String a = m_dynamicParameter.assignment(); String sv = value.toString(); @@ -71,15 +77,15 @@ public class WrappedParameter { "Dynamic parameter expected a value of the form a" + a + "b" + " but got:" + sv); } - callPut(object, field, sv.substring(0, aInd), sv.substring(aInd + 1)); + callPut(object, parameterized, sv.substring(0, aInd), sv.substring(aInd + 1)); } } - private void callPut(Object object, Field field, String key, String value) { + private void callPut(Object object, Parameterized parameterized, String key, String value) { try { Method m; - m = findPut(field.getType()); - m.invoke(field.get(object), key, value); + m = findPut(parameterized.getType()); + m.invoke(parameterized.get(object), key, value); } catch (SecurityException e) { e.printStackTrace(); } catch(IllegalAccessException e) { -- cgit v1.2.3 From c675ef5201552ed809a1cb12e18f2fc3e25a7c9a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 4 Jul 2012 13:23:31 -0700 Subject: Added: @Parameter(help = true) --- src/main/java/com/beust/jcommander/JCommander.java | 11 +++++++++++ src/main/java/com/beust/jcommander/Parameter.java | 5 +++++ src/main/java/com/beust/jcommander/ParameterDescription.java | 4 ++++ src/main/java/com/beust/jcommander/WrappedParameter.java | 4 ++++ 4 files changed, 24 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 66ce5f5..63b935c 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -146,6 +146,8 @@ public class JCommander { }; private int m_columnSize = 79; + + private boolean m_helpWasSpecified; private static Console m_console; @@ -299,6 +301,11 @@ public class JCommander { * Make sure that all the required parameters have received a value. */ private void validateOptions() { + // No validation if we found a help parameter + if (m_helpWasSpecified) { + return; + } + if (! m_requiredFields.isEmpty()) { StringBuilder missingFields = new StringBuilder(); for (ParameterDescription pd : m_requiredFields.values()) { @@ -706,6 +713,10 @@ public class JCommander { } else { increment = processFixedArity(args, i, pd, fieldType); } + // If it's a help option, remember for later + if (pd.isHelp()) { + m_helpWasSpecified = true; + } } } } else { diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 51b941f..974eeaa 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -114,4 +114,9 @@ public @interface Parameter { */ boolean echoInput() default false; + /** + * If true, this parameter is for help. If such a parameter is specified, + * required parameters are no longer checked for their presence. + */ + boolean help() default false; } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 5f4a0a7..6480ea7 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -345,4 +345,8 @@ public class ParameterDescription { public boolean isDynamicParameter() { return m_dynamicParameterAnnotation != null; } + + public boolean isHelp() { + return m_wrappedParameter.isHelp(); + } } diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index 1f690a0..52cafc4 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -105,4 +105,8 @@ public class WrappedParameter { return m_dynamicParameter != null ? m_dynamicParameter.assignment() : ""; } + public boolean isHelp() { + return m_parameter != null && m_parameter.help(); + } + } -- cgit v1.2.3 From e0c1cdc5cea32d7551cf92069adfd529fc48a756 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Fri, 6 Jul 2012 23:26:16 -0700 Subject: If a setter throws ParameterException, don't wrap it into another ParameterException. --- src/main/java/com/beust/jcommander/Parameterized.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameterized.java b/src/main/java/com/beust/jcommander/Parameterized.java index ec698fa..302d2b6 100644 --- a/src/main/java/com/beust/jcommander/Parameterized.java +++ b/src/main/java/com/beust/jcommander/Parameterized.java @@ -178,7 +178,12 @@ public class Parameterized { } catch (IllegalAccessException ex) { throw new ParameterException(ex); } catch (InvocationTargetException ex) { - throw new ParameterException(ex); + // If a ParameterException was thrown, don't wrap it into another one + if (ex.getTargetException() instanceof ParameterException) { + throw (ParameterException) ex.getTargetException(); + } else { + throw new ParameterException(ex); + } } } -- cgit v1.2.3 From 6e35863858ca9c8c0584a98797981bfa9867ff02 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 7 Jul 2012 08:57:33 -0700 Subject: Make getter methods optional. --- src/main/java/com/beust/jcommander/Parameterized.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameterized.java b/src/main/java/com/beust/jcommander/Parameterized.java index 302d2b6..14ce975 100644 --- a/src/main/java/com/beust/jcommander/Parameterized.java +++ b/src/main/java/com/beust/jcommander/Parameterized.java @@ -117,7 +117,7 @@ public class Parameterized { } catch (SecurityException e) { throw new ParameterException(e); } catch (NoSuchMethodException e) { - throw new ParameterException(e); + return null; } catch (IllegalArgumentException e) { throw new ParameterException(e); } catch (IllegalAccessException e) { -- cgit v1.2.3 From f4ed64c254096dd10305a92c4d96656048f35b15 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 7 Jul 2012 14:07:14 -0700 Subject: If we have a setter but no getter, try to find a field to calculate the default value. --- src/main/java/com/beust/jcommander/Parameterized.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameterized.java b/src/main/java/com/beust/jcommander/Parameterized.java index 14ce975..ff8753b 100644 --- a/src/main/java/com/beust/jcommander/Parameterized.java +++ b/src/main/java/com/beust/jcommander/Parameterized.java @@ -117,7 +117,22 @@ public class Parameterized { } catch (SecurityException e) { throw new ParameterException(e); } catch (NoSuchMethodException e) { - return null; + // Try to find a field + String name = m_method.getName(); + String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4); + Object result = null; + try { + Field field = m_method.getDeclaringClass().getDeclaredField(fieldName); + if (field != null) { + field.setAccessible(true); + result = field.get(object); + } + } catch(NoSuchFieldException ex) { + // ignore + } catch(IllegalAccessException ex) { + // ignore + } + return result; } catch (IllegalArgumentException e) { throw new ParameterException(e); } catch (IllegalAccessException e) { -- cgit v1.2.3 From dfb5854988a7ad9cf54ddf101c7fbbff1df3c205 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 7 Jul 2012 15:21:37 -0700 Subject: Added JCommander#setVerbose. --- src/main/java/com/beust/jcommander/JCommander.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 63b935c..71bac67 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -791,6 +791,8 @@ public class JCommander { } private final IVariableArity DEFAULT_VARIABLE_ARITY = new DefaultVariableArity(); + private int m_verbose = 0; + /** * @return the number of options that were processed. */ @@ -1152,7 +1154,7 @@ public class JCommander { } private void p(String string) { - if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) { + if (m_verbose > 0 || System.getProperty(JCommander.DEBUG_PROPERTY) != null) { getConsole().println("[JCommander] " + string); } } @@ -1493,5 +1495,9 @@ public class JCommander { } } + + public void setVerbose(int verbose) { + m_verbose = verbose; + } } -- cgit v1.2.3 From e97a09f79f6947d4499de3ae54eebc4299a94641 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 7 Jul 2012 15:41:12 -0700 Subject: Misc clean up. --- src/main/java/com/beust/jcommander/JCommander.java | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 71bac67..cc80420 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -27,6 +27,7 @@ import com.beust.jcommander.internal.DefaultConverterFactory; import com.beust.jcommander.internal.JDK6Console; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; +import com.beust.jcommander.internal.Nullable; import java.io.BufferedReader; import java.io.FileReader; @@ -48,8 +49,6 @@ import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; - - /** * The main class for JCommander. It's responsible for parsing the object that contains * all the annotated fields, parse the command line and assign the fields with the correct @@ -60,7 +59,7 @@ import java.util.ResourceBundle; * or an instance of Iterable. In the case of an array or Iterable, JCommander will collect * the \@Parameter annotations from all the objects passed in parameter. * - * @author cbeust + * @author Cedric Beust */ public class JCommander { public static final String DEBUG_PROPERTY = "jcommander.debug"; @@ -104,7 +103,7 @@ public class JCommander { private Map m_requiredFields = Maps.newHashMap(); /** - * A map of all the parameterized fields/methods/ + * A map of all the parameterized fields/methods. */ private Map m_fields = Maps.newHashMap(); @@ -119,6 +118,7 @@ public class JCommander { * List of commands and their instance. */ private Map m_commands = Maps.newLinkedHashMap(); + /** * Alias database for reverse lookup */ @@ -178,7 +178,7 @@ public class JCommander { * @param object The arg object expected to contain {@link Parameter} annotations. * @param bundle The bundle to use for the descriptions. Can be null. */ - public JCommander(Object object, ResourceBundle bundle) { + public JCommander(Object object, @Nullable ResourceBundle bundle) { addObject(object); setDescriptionsBundle(bundle); } @@ -1188,11 +1188,11 @@ public class JCommander { } /** - * @param field The field * @param type The type of the actual parameter * @param value The value to convert */ - public Object convertValue(Parameterized parameterized, Class type, String value) { + public Object convertValue(Parameterized parameterized, Class type, + String value) { Parameter annotation = parameterized.getParameter(); // Do nothing if it's a @DynamicParameter @@ -1313,9 +1313,11 @@ public class JCommander { IStringConverter result = stringCtor != null ? stringCtor.newInstance(optionName) - : ctor.newInstance(); + : (ctor != null + ? ctor.newInstance() + : null); - return result; + return result; } /** @@ -1430,6 +1432,9 @@ public class JCommander { return jc; } + /** + * Encapsulation of either a main application or an individual command. + */ private static final class ProgramName { private final String m_name; private final List m_aliases; -- cgit v1.2.3 From 75d579a2fc672582cfadefc360fe18b05caa7e21 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 8 Jul 2012 10:37:23 -0700 Subject: Forgot Nullable.java --- src/main/java/com/beust/jcommander/internal/Nullable.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/internal/Nullable.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/internal/Nullable.java b/src/main/java/com/beust/jcommander/internal/Nullable.java new file mode 100644 index 0000000..b988373 --- /dev/null +++ b/src/main/java/com/beust/jcommander/internal/Nullable.java @@ -0,0 +1,12 @@ +package com.beust.jcommander.internal; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.PARAMETER; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +@Target({FIELD, PARAMETER}) +public @interface Nullable { +} -- cgit v1.2.3 From 94e08e73342f858518b14a70624c38479c0365d3 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 17 Jul 2012 22:25:26 -0700 Subject: Fixed: Parameters with a single double quote were not working properly --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index cc80420..9a751ba 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -497,7 +497,7 @@ public class JCommander { */ private static String trim(String string) { String result = string.trim(); - if (result.startsWith("\"") && result.endsWith("\"")) { + if (result.startsWith("\"") && result.endsWith("\"") && result.length() > 1) { result = result.substring(1, result.length() - 1); } return result; -- cgit v1.2.3 From f65b16085ead5063dbb7c9a6f366ebedb2227f68 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 17 Jul 2012 22:44:09 -0700 Subject: Fixed: Bugs with the PositiveInteger validator --- src/main/java/com/beust/jcommander/ParameterDescription.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 6480ea7..d886e30 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -302,6 +302,8 @@ public class ParameterDescription { throw new ParameterException("Can't instantiate validator:" + e); } catch (IllegalAccessException e) { throw new ParameterException("Can't instantiate validator:" + e); + } catch(Exception ex) { + throw new ParameterException(ex); } } -- cgit v1.2.3 From e79760c8a3806df3369adcbaa4dbaeceb93f9a65 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 25 Jul 2012 14:53:22 -0700 Subject: Fixed: Empty string defaults now displayed as "" in the usage --- src/main/java/com/beust/jcommander/JCommander.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 9a751ba..bd9bad8 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1071,9 +1071,12 @@ public class JCommander { + "key" + parameter.getAssignment() + "value"); } - if (def != null && ! "".equals(def)) { + if (def != null) { + String displayedDef = Strings.isStringEmpty(def.toString()) + ? "" + : def.toString(); out.append("\n" + spaces(indentCount + 1)) - .append("Default: " + (parameter.password()?"********":def)); + .append("Default: " + (parameter.password()?"********" : displayedDef)); } out.append("\n"); } -- cgit v1.2.3 From e0de481742a2d1ef7454c9bf462753bcb756507e Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 30 Jul 2012 22:09:42 -0700 Subject: Removed the duplicate spaces() method. --- src/main/java/com/beust/jcommander/JCommander.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bd9bad8..bc0e658 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1066,7 +1066,7 @@ public class JCommander { wrapDescription(out, indentCount, pd.getDescription()); Object def = pd.getDefault(); if (pd.isDynamicParameter()) { - out.append("\n" + spaces(indentCount + 1)) + out.append("\n" + s(indentCount + 1)) .append("Syntax: " + parameter.names()[0] + "key" + parameter.getAssignment() + "value"); @@ -1075,7 +1075,7 @@ public class JCommander { String displayedDef = Strings.isStringEmpty(def.toString()) ? "" : def.toString(); - out.append("\n" + spaces(indentCount + 1)) + out.append("\n" + s(indentCount + 1)) .append("Default: " + (parameter.password()?"********" : displayedDef)); } out.append("\n"); @@ -1127,19 +1127,13 @@ public class JCommander { out.append(" ").append(word); current += word.length() + 1; } else { - out.append("\n").append(spaces(indent + 1)).append(word); + out.append("\n").append(s(indent + 1)).append(word); current = indent; } i++; } } - private String spaces(int indent) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < indent; i++) sb.append(" "); - return sb.toString(); - } - /** * @return a Collection of all the \@Parameter annotations found on the * target class. This can be used to display the usage() in a different -- cgit v1.2.3 From 5f260731d31e274e89cf01ba71b26f0423192baf Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 30 Jul 2012 22:23:27 -0700 Subject: Description of commands is now displayed on the next line and indented. Makes long descriptions easier to read. --- src/main/java/com/beust/jcommander/JCommander.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bc0e658..8c8072e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1053,16 +1053,16 @@ public class JCommander { // // Display all the names and descriptions // + int descriptionIndent = 6; if (sorted.size() > 0) out.append(indent).append("\n").append(indent).append(" Options:\n"); for (ParameterDescription pd : sorted) { - int l = pd.getNames().length(); - int spaceCount = longestName - l; - int start = out.length(); WrappedParameter parameter = pd.getParameter(); out.append(indent).append(" " + (parameter.required() ? "* " : " ") - + pd.getNames() + s(spaceCount)); - int indentCount = out.length() - start; + + pd.getNames() + + "\n" + + indent + s(descriptionIndent)); + int indentCount = indent.length() + descriptionIndent; wrapDescription(out, indentCount, pd.getDescription()); Object def = pd.getDefault(); if (pd.isDynamicParameter()) { -- cgit v1.2.3 From a8f4de2555e41fad6cab4fbcff4e91cc32350db7 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 31 Jul 2012 11:24:27 -0700 Subject: Added: JCommander#setCaseSensitiveOptions (default: true) --- src/main/java/com/beust/jcommander/JCommander.java | 51 ++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 8c8072e..69a4a3e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -682,7 +682,7 @@ public class JCommander { // // Option // - ParameterDescription pd = m_descriptions.get(a); + ParameterDescription pd = findParameterDescription(a); if (pd != null) { if (pd.getParameter().password()) { @@ -793,6 +793,9 @@ public class JCommander { private int m_verbose = 0; + private boolean m_caseSensitiveOptions = true; + private boolean m_caseSensitiveCommands = true; + /** * @return the number of options that were processed. */ @@ -1412,15 +1415,49 @@ public class JCommander { return m_objects; } + private V findCaseSensitiveMap(Map map, String name) { + if (m_caseSensitiveOptions) { + return map.get(name); + } else { + for (String c : map.keySet()) { + if (c.equalsIgnoreCase(name)) { + return map.get(c); + } + } + } + return null; + } + + private ParameterDescription findParameterDescription(String arg) { + return findCaseSensitiveMap(m_descriptions, arg); + } + + private JCommander findCommand(ProgramName name) { + if (! m_caseSensitiveCommands) { + return m_commands.get(name); + } else { + for (ProgramName c : m_commands.keySet()) { + if (c.getName().equalsIgnoreCase(name.getName())) { + return m_commands.get(c); + } + } + } + return null; + } + + private ProgramName findProgramName(String name) { + return findCaseSensitiveMap(aliasMap, name); + } + /* * Reverse lookup JCommand object by command's name or its alias */ private JCommander findCommandByAlias(String commandOrAlias) { - ProgramName progName = aliasMap.get(commandOrAlias); + ProgramName progName = findProgramName(commandOrAlias); if (progName == null) { return null; } - JCommander jc = m_commands.get(progName); + JCommander jc = findCommand(progName); if (jc == null) { throw new IllegalStateException( "There appears to be inconsistency in the internal command database. " + @@ -1501,5 +1538,13 @@ public class JCommander { public void setVerbose(int verbose) { m_verbose = verbose; } + + public void setCaseSensitiveOptions(boolean b) { + m_caseSensitiveOptions = b; + } + +// public void setCaseSensitiveCommands(boolean b) { +// m_caseSensitiveCommands = b; +// } } -- cgit v1.2.3 From 2c092c0c1966a21f1b585eac22b4e36045a43549 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 1 Aug 2012 08:50:32 -0700 Subject: Added: JCommander#allowAbbreviatedOptions (default: false) --- src/main/java/com/beust/jcommander/JCommander.java | 43 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 69a4a3e..6060dfc 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -795,6 +795,7 @@ public class JCommander { private boolean m_caseSensitiveOptions = true; private boolean m_caseSensitiveCommands = true; + private boolean m_allowAbbreviatedOptions = false; /** * @return the number of options that were processed. @@ -1415,13 +1416,43 @@ public class JCommander { return m_objects; } + private V findAbbreviatedOption(Map map, String name, boolean caseSensitive) { + Map results = Maps.newHashMap(); + for (String c : map.keySet()) { + boolean match = (caseSensitive && c.startsWith(name)) + || ((! caseSensitive) && c.toLowerCase().startsWith(name.toLowerCase())); + if (match) { + results.put(c, map.get(c)); + } + } + V result; + if (results.size() > 1) { + throw new ParameterException("Ambiguous option: " + name + + " matches " + results.keySet()); + } else if (results.size() == 1) { + result = results.values().iterator().next(); + } else { + result = null; + } + + return result; + } + private V findCaseSensitiveMap(Map map, String name) { if (m_caseSensitiveOptions) { - return map.get(name); + if (m_allowAbbreviatedOptions) { + return findAbbreviatedOption(map, name, m_caseSensitiveOptions); + } else { + return map.get(name); + } } else { - for (String c : map.keySet()) { - if (c.equalsIgnoreCase(name)) { - return map.get(c); + if (m_allowAbbreviatedOptions) { + return findAbbreviatedOption(map, name, m_caseSensitiveOptions); + } else { + for (String c : map.keySet()) { + if (c.equalsIgnoreCase(name)) { + return map.get(c); + } } } } @@ -1543,6 +1574,10 @@ public class JCommander { m_caseSensitiveOptions = b; } + public void setAllowAbbreviatedOptions(boolean b) { + m_allowAbbreviatedOptions = b; + } + // public void setCaseSensitiveCommands(boolean b) { // m_caseSensitiveCommands = b; // } -- cgit v1.2.3 From 18acf239feebe9f079a4d31e1852556b7cd2fd4c Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 1 Aug 2012 09:23:01 -0700 Subject: Moved the finder tests in their own class. --- src/main/java/com/beust/jcommander/JCommander.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 6060dfc..fccbb9e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -794,7 +794,6 @@ public class JCommander { private int m_verbose = 0; private boolean m_caseSensitiveOptions = true; - private boolean m_caseSensitiveCommands = true; private boolean m_allowAbbreviatedOptions = false; /** @@ -1464,7 +1463,7 @@ public class JCommander { } private JCommander findCommand(ProgramName name) { - if (! m_caseSensitiveCommands) { + if (! m_caseSensitiveOptions) { return m_commands.get(name); } else { for (ProgramName c : m_commands.keySet()) { -- cgit v1.2.3 From dbccffb3047aa721e3c09ecda4e6b12a00152dd1 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 1 Aug 2012 10:45:27 -0700 Subject: Refactoring: introducing FuzzyMap and IKey. --- src/main/java/com/beust/jcommander/FuzzyMap.java | 61 ++++++++++++++ src/main/java/com/beust/jcommander/JCommander.java | 94 +++++++--------------- src/main/java/com/beust/jcommander/StringKey.java | 48 +++++++++++ 3 files changed, 138 insertions(+), 65 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/FuzzyMap.java create mode 100644 src/main/java/com/beust/jcommander/StringKey.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/FuzzyMap.java b/src/main/java/com/beust/jcommander/FuzzyMap.java new file mode 100644 index 0000000..5f3939b --- /dev/null +++ b/src/main/java/com/beust/jcommander/FuzzyMap.java @@ -0,0 +1,61 @@ +package com.beust.jcommander; + +import com.beust.jcommander.internal.Maps; + +import java.util.Map; + +/** + * Helper class to perform fuzzy key look ups: looking up case insensitive or + * abbreviated keys. + */ +public class FuzzyMap { + interface IKey { + String getName(); + } + + public static V findInMap(Map map, IKey name, + boolean caseSensitive, boolean allowAbbreviations) { + if (allowAbbreviations) { + return findAbbreviatedValue(map, name, caseSensitive); + } else { + if (caseSensitive) { + return map.get(name); + } else { + for (IKey c : map.keySet()) { + if (c.getName().equalsIgnoreCase(name.getName())) { + return map.get(c); + } + } + } + } + return null; + } + + private static V findAbbreviatedValue(Map map, IKey name, + boolean caseSensitive) { + String string = name.getName(); + Map results = Maps.newHashMap(); + for (IKey c : map.keySet()) { + String n = c.getName(); + boolean match = (caseSensitive && n.startsWith(string)) + || ((! caseSensitive) && n.toLowerCase().startsWith(string.toLowerCase())); + if (match) { + results.put(n, map.get(c)); + } + } + + V result; + if (results.size() > 1) { + throw new ParameterException("Ambiguous option: " + name + + " matches " + results.keySet()); + } else if (results.size() == 1) { + result = results.values().iterator().next(); + } else { + result = null; + } + + return result; + } + + +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index fccbb9e..bfda67f 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -18,6 +18,7 @@ package com.beust.jcommander; +import com.beust.jcommander.FuzzyMap.IKey; import com.beust.jcommander.converters.IParameterSplitter; import com.beust.jcommander.converters.NoConverter; import com.beust.jcommander.converters.StringConverter; @@ -67,7 +68,7 @@ public class JCommander { /** * A map to look up parameter description per option name. */ - private Map m_descriptions; + private Map m_descriptions; /** * The objects that contain fields annotated with @Parameter. @@ -122,7 +123,7 @@ public class JCommander { /** * Alias database for reverse lookup */ - private Map aliasMap = Maps.newLinkedHashMap(); + private Map aliasMap = Maps.newLinkedHashMap(); /** * The name of the command after the parsing has run. @@ -399,8 +400,8 @@ public class JCommander { } private ParameterDescription getPrefixDescriptionFor(String arg) { - for (Map.Entry es : m_descriptions.entrySet()) { - if (arg.startsWith(es.getKey())) return es.getValue(); + for (Map.Entry es : m_descriptions.entrySet()) { + if (arg.startsWith(es.getKey().getName())) return es.getValue(); } return null; @@ -539,14 +540,14 @@ public class JCommander { new ParameterDescription(object, p, parameterized, m_bundle, this); } else { for (String name : p.names()) { - if (m_descriptions.containsKey(name)) { + if (m_descriptions.containsKey(new StringKey(name))) { throw new ParameterException("Found the option " + name + " multiple times"); } p("Adding description for " + name); ParameterDescription pd = new ParameterDescription(object, p, parameterized, m_bundle, this); m_fields.put(parameterized, pd); - m_descriptions.put(name, pd); + m_descriptions.put(new StringKey(name), pd); if (p.required()) m_requiredFields.put(parameterized, pd); } @@ -574,7 +575,7 @@ public class JCommander { ParameterDescription pd = new ParameterDescription(object, dp, parameterized, m_bundle, this); m_fields.put(parameterized, pd); - m_descriptions.put(name, pd); + m_descriptions.put(new StringKey(name), pd); if (dp.required()) m_requiredFields.put(parameterized, pd); } @@ -1356,8 +1357,9 @@ public class JCommander { //Note: Name clash check is intentionally omitted to resemble the // original behaviour of clashing commands. // Aliases are, however, are strictly checked for name clashes. - aliasMap.put(name, progName); - for (String alias : aliases) { + aliasMap.put(new StringKey(name), progName); + for (String a : aliases) { + IKey alias = new StringKey(a); //omit pointless aliases to avoid name clash exception if (!alias.equals(name)) { ProgramName mappedName = aliasMap.get(alias); @@ -1415,68 +1417,29 @@ public class JCommander { return m_objects; } - private V findAbbreviatedOption(Map map, String name, boolean caseSensitive) { - Map results = Maps.newHashMap(); - for (String c : map.keySet()) { - boolean match = (caseSensitive && c.startsWith(name)) - || ((! caseSensitive) && c.toLowerCase().startsWith(name.toLowerCase())); - if (match) { - results.put(c, map.get(c)); - } - } - V result; - if (results.size() > 1) { - throw new ParameterException("Ambiguous option: " + name - + " matches " + results.keySet()); - } else if (results.size() == 1) { - result = results.values().iterator().next(); - } else { - result = null; - } - - return result; - } - - private V findCaseSensitiveMap(Map map, String name) { - if (m_caseSensitiveOptions) { - if (m_allowAbbreviatedOptions) { - return findAbbreviatedOption(map, name, m_caseSensitiveOptions); - } else { - return map.get(name); - } - } else { - if (m_allowAbbreviatedOptions) { - return findAbbreviatedOption(map, name, m_caseSensitiveOptions); - } else { - for (String c : map.keySet()) { - if (c.equalsIgnoreCase(name)) { - return map.get(c); - } - } - } - } - return null; - } - private ParameterDescription findParameterDescription(String arg) { - return findCaseSensitiveMap(m_descriptions, arg); + return FuzzyMap.findInMap(m_descriptions, new StringKey(arg), m_caseSensitiveOptions, + m_allowAbbreviatedOptions); } private JCommander findCommand(ProgramName name) { - if (! m_caseSensitiveOptions) { - return m_commands.get(name); - } else { - for (ProgramName c : m_commands.keySet()) { - if (c.getName().equalsIgnoreCase(name.getName())) { - return m_commands.get(c); - } - } - } - return null; + return FuzzyMap.findInMap(m_commands, name, + m_caseSensitiveOptions, m_allowAbbreviatedOptions); +// if (! m_caseSensitiveOptions) { +// return m_commands.get(name); +// } else { +// for (ProgramName c : m_commands.keySet()) { +// if (c.getName().equalsIgnoreCase(name.getName())) { +// return m_commands.get(c); +// } +// } +// } +// return null; } private ProgramName findProgramName(String name) { - return findCaseSensitiveMap(aliasMap, name); + return FuzzyMap.findInMap(aliasMap, new StringKey(name), + m_caseSensitiveOptions, m_allowAbbreviatedOptions); } /* @@ -1499,7 +1462,7 @@ public class JCommander { /** * Encapsulation of either a main application or an individual command. */ - private static final class ProgramName { + private static final class ProgramName implements IKey { private final String m_name; private final List m_aliases; @@ -1508,6 +1471,7 @@ public class JCommander { m_aliases = aliases; } + @Override public String getName() { return m_name; } diff --git a/src/main/java/com/beust/jcommander/StringKey.java b/src/main/java/com/beust/jcommander/StringKey.java new file mode 100644 index 0000000..09d1149 --- /dev/null +++ b/src/main/java/com/beust/jcommander/StringKey.java @@ -0,0 +1,48 @@ +package com.beust.jcommander; + +import com.beust.jcommander.FuzzyMap.IKey; + +public class StringKey implements IKey { + + private String m_name; + + public StringKey(String name) { + m_name = name; + } + + @Override + public String getName() { + return m_name; + } + + @Override + public String toString() { + return m_name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StringKey other = (StringKey) obj; + if (m_name == null) { + if (other.m_name != null) + return false; + } else if (!m_name.equals(other.m_name)) + return false; + return true; + } + +} -- cgit v1.2.3 From a62e9f5644875c88737a17308adca7775fdb1450 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 2 Aug 2012 10:22:16 -0700 Subject: Don't wrap a ParameterException in a ParameterException. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index d886e30..7fd568c 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -302,6 +302,8 @@ public class ParameterDescription { throw new ParameterException("Can't instantiate validator:" + e); } catch (IllegalAccessException e) { throw new ParameterException("Can't instantiate validator:" + e); + } catch(ParameterException ex) { + throw ex; } catch(Exception ex) { throw new ParameterException(ex); } -- cgit v1.2.3 From 3dd7558e2aee86e647b4530f536cbb1fa574b87a Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 5 Aug 2012 23:50:48 -0700 Subject: Make getParameter() public. --- src/main/java/com/beust/jcommander/ParameterDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 7fd568c..a49562f 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -192,7 +192,7 @@ public class ParameterDescription { return sb.toString(); } - WrappedParameter getParameter() { + public WrappedParameter getParameter() { return m_wrappedParameter; } -- cgit v1.2.3 From 5377e48b0f7b1b77aa9d546313b11767559068de Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 7 Aug 2012 04:29:57 -0700 Subject: IParameterValidator2. --- .../com/beust/jcommander/IParameterValidator2.java | 34 ++++++++++++++++++++++ src/main/java/com/beust/jcommander/JCommander.java | 3 +- .../com/beust/jcommander/ParameterDescription.java | 9 ++++-- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/beust/jcommander/IParameterValidator2.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/IParameterValidator2.java b/src/main/java/com/beust/jcommander/IParameterValidator2.java new file mode 100644 index 0000000..77e7dd3 --- /dev/null +++ b/src/main/java/com/beust/jcommander/IParameterValidator2.java @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2011 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander; + +public interface IParameterValidator2 extends IParameterValidator { + + /** + * Validate the parameter. + * + * @param name The name of the parameter (e.g. "-host"). + * @param value The value of the parameter that we need to validate + * @param pd The description of this parameter + * + * @throws ParameterException Thrown if the value of the parameter is invalid. + */ + void validate(String name, String value, ParameterDescription pd) throws ParameterException; + +} diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index bfda67f..30b9b4a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -745,7 +745,8 @@ public class JCommander { } } - ParameterDescription.validateParameter(m_mainParameterAnnotation.validateWith(), + ParameterDescription.validateParameter(m_mainParameterDescription, + m_mainParameterAnnotation.validateWith(), "Default", value); m_mainParameterDescription.setAssigned(true); diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index a49562f..33574a9 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -266,7 +266,7 @@ public class ParameterDescription { private void validateParameter(String name, String value) { Class validator = m_wrappedParameter.validateWith(); if (validator != null) { - validateParameter(validator, name, value); + validateParameter(this, validator, name, value); } } @@ -291,13 +291,18 @@ public class ParameterDescription { } } - public static void validateParameter(Class validator, + public static void validateParameter(ParameterDescription pd, + Class validator, String name, String value) { try { if (validator != NoValidator.class) { p("Validating parameter:" + name + " value:" + value + " validator:" + validator); } validator.newInstance().validate(name, value); + if (IParameterValidator2.class.isAssignableFrom(validator)) { + IParameterValidator2 instance = (IParameterValidator2) validator.newInstance(); + instance.validate(name, value, pd); + } } catch (InstantiationException e) { throw new ParameterException("Can't instantiate validator:" + e); } catch (IllegalAccessException e) { -- cgit v1.2.3 From 8a4c3d11d8d74628fbe55dce61771810a841723e Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Thu, 16 Aug 2012 10:33:26 -0700 Subject: Don't throw an exception if running in "no validation" mode. --- src/main/java/com/beust/jcommander/JCommander.java | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 30b9b4a..8965f3b 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -273,7 +273,7 @@ public class JCommander { if (m_descriptions == null) createDescriptions(); initializeDefaultValues(); - parseValues(expandArgs(args)); + parseValues(expandArgs(args), validate); if (validate) validateOptions(); } @@ -666,7 +666,7 @@ public class JCommander { /** * Main method that parses the values and initializes the fields accordingly. */ - private void parseValues(String[] args) { + private void parseValues(String[] args, boolean validate) { // This boolean becomes true if we encounter a command, which indicates we need // to stop parsing (the parsing of the command will be done in a sub JCommander // object) @@ -756,15 +756,18 @@ public class JCommander { // // Command parsing // - if (jc == null) throw new MissingCommandException("Expected a command, got " + arg); - m_parsedCommand = jc.m_programName.m_name; - m_parsedAlias = arg; //preserve the original form - - // Found a valid command, ask it to parse the remainder of the arguments. - // Setting the boolean commandParsed to true will force the current - // loop to end. - jc.parse(subArray(args, i + 1)); - commandParsed = true; + if (jc == null && validate) { + throw new MissingCommandException("Expected a command, got " + arg); + } else if (jc != null){ + m_parsedCommand = jc.m_programName.m_name; + m_parsedAlias = arg; //preserve the original form + + // Found a valid command, ask it to parse the remainder of the arguments. + // Setting the boolean commandParsed to true will force the current + // loop to end. + jc.parse(subArray(args, i + 1)); + commandParsed = true; + } } } } -- cgit v1.2.3 From c36c84f608a9a0f3877b37e2889bff6d8a1da88d Mon Sep 17 00:00:00 2001 From: Sergey Tyurin Date: Mon, 17 Sep 2012 22:03:11 +0600 Subject: Fix usage() to print missing new-line characters. The change affects the result of usage() when: - there are commands and no main parameters - there are commands without parameters --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 8965f3b..16ca88e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1032,10 +1032,10 @@ public class JCommander { String programName = m_programName != null ? m_programName.getDisplayName() : "
"; out.append(indent).append("Usage: " + programName + " [options]"); if (hasCommands) out.append(indent).append(" [command] [command options]"); -// out.append("\n"); if (m_mainParameterDescription != null) { out.append(" " + m_mainParameterDescription.getDescription()); } + out.append("\n"); // // Align the descriptions at the "longestName" column @@ -1062,7 +1062,7 @@ public class JCommander { // Display all the names and descriptions // int descriptionIndent = 6; - if (sorted.size() > 0) out.append(indent).append("\n").append(indent).append(" Options:\n"); + if (sorted.size() > 0) out.append(indent).append(" Options:\n"); for (ParameterDescription pd : sorted) { WrappedParameter parameter = pd.getParameter(); out.append(indent).append(" " -- cgit v1.2.3 From c421118d3104c0594dbe207c8443e51022422d32 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 17 Sep 2012 23:01:04 -0700 Subject: Added JCommander#setNoThrow() and JCommander#getUnknownArgs(). --- src/main/java/com/beust/jcommander/JCommander.java | 46 ++++++++++++++++------ .../java/com/beust/jcommander/internal/Lists.java | 5 +++ 2 files changed, 38 insertions(+), 13 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 8965f3b..f1717be 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -18,18 +18,6 @@ package com.beust.jcommander; -import com.beust.jcommander.FuzzyMap.IKey; -import com.beust.jcommander.converters.IParameterSplitter; -import com.beust.jcommander.converters.NoConverter; -import com.beust.jcommander.converters.StringConverter; -import com.beust.jcommander.internal.Console; -import com.beust.jcommander.internal.DefaultConsole; -import com.beust.jcommander.internal.DefaultConverterFactory; -import com.beust.jcommander.internal.JDK6Console; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; -import com.beust.jcommander.internal.Nullable; - import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; @@ -50,6 +38,18 @@ import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; +import com.beust.jcommander.FuzzyMap.IKey; +import com.beust.jcommander.converters.IParameterSplitter; +import com.beust.jcommander.converters.NoConverter; +import com.beust.jcommander.converters.StringConverter; +import com.beust.jcommander.internal.Console; +import com.beust.jcommander.internal.DefaultConsole; +import com.beust.jcommander.internal.DefaultConverterFactory; +import com.beust.jcommander.internal.JDK6Console; +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; +import com.beust.jcommander.internal.Nullable; + /** * The main class for JCommander. It's responsible for parsing the object that contains * all the annotated fields, parse the command line and assign the fields with the correct @@ -149,6 +149,9 @@ public class JCommander { private int m_columnSize = 79; private boolean m_helpWasSpecified; + + private List m_unknownArgs = Lists.newArrayList(); + private boolean m_noThrow; private static Console m_console; @@ -721,7 +724,16 @@ public class JCommander { } } } else { - throw new ParameterException("Unknown option: " + arg); + if (m_noThrow) { + m_unknownArgs.add(arg); + i++; + while (i < args.length && ! isOption(args, args[i])) { + m_unknownArgs.add(args[i++]); + } + increment = 0; + } else { + throw new ParameterException("Unknown option: " + arg); + } } } else { @@ -1545,6 +1557,14 @@ public class JCommander { m_allowAbbreviatedOptions = b; } + public void setNoThrow(boolean b) { + m_noThrow = b; + } + + public List getUnknownArgs() { + return m_unknownArgs; + } + // public void setCaseSensitiveCommands(boolean b) { // m_caseSensitiveCommands = b; // } diff --git a/src/main/java/com/beust/jcommander/internal/Lists.java b/src/main/java/com/beust/jcommander/internal/Lists.java index c4017c0..fdbee55 100644 --- a/src/main/java/com/beust/jcommander/internal/Lists.java +++ b/src/main/java/com/beust/jcommander/internal/Lists.java @@ -19,6 +19,7 @@ package com.beust.jcommander.internal; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -33,6 +34,10 @@ public class Lists { return new ArrayList(c); } + public static List newArrayList(K... c) { + return new ArrayList(Arrays.asList(c)); + } + public static List newArrayList(int size) { return new ArrayList(size); } -- cgit v1.2.3 From 406904b81e91c3160646388b26f7c167fa7dd3ea Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 18 Sep 2012 18:44:38 -0700 Subject: Rename: noThrow -> acceptUnknownOption. --- src/main/java/com/beust/jcommander/JCommander.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 45392f5..3f6853d 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -151,7 +151,7 @@ public class JCommander { private boolean m_helpWasSpecified; private List m_unknownArgs = Lists.newArrayList(); - private boolean m_noThrow; + private boolean m_acceptUnknownOptions = false; private static Console m_console; @@ -724,7 +724,7 @@ public class JCommander { } } } else { - if (m_noThrow) { + if (m_acceptUnknownOptions) { m_unknownArgs.add(arg); i++; while (i < args.length && ! isOption(args, args[i])) { @@ -1557,8 +1557,8 @@ public class JCommander { m_allowAbbreviatedOptions = b; } - public void setNoThrow(boolean b) { - m_noThrow = b; + public void setAcceptUnknownOptions(boolean b) { + m_acceptUnknownOptions = b; } public List getUnknownArgs() { -- cgit v1.2.3 From 31f61c5de3753a86d58a5bf2399ea5ea7312d35b Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 18 Sep 2012 22:12:45 -0700 Subject: Renaming. --- src/main/java/com/beust/jcommander/JCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3f6853d..1b49ae7 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1561,7 +1561,7 @@ public class JCommander { m_acceptUnknownOptions = b; } - public List getUnknownArgs() { + public List getUnknownOptions() { return m_unknownArgs; } -- cgit v1.2.3 From 5fc805c44e904eb37f24217676b5da1619268c48 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 23 Sep 2012 06:10:45 -0700 Subject: Added enum support (Scott M. Stark). --- src/main/java/com/beust/jcommander/JCommander.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1b49ae7..efde39e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1235,6 +1235,10 @@ public class JCommander { converterClass = elementType != null ? findConverter((Class>) elementType) : StringConverter.class; + // Check for enum type parameter + if (converterClass == null && Enum.class.isAssignableFrom((Class) elementType)) { + converterClass = (Class>) elementType; + } } // @@ -1257,7 +1261,7 @@ public class JCommander { try { String[] names = annotation.names(); String optionName = names.length > 0 ? names[0] : "[Main class]"; - if (converterClass.isEnum()) { + if (converterClass != null && converterClass.isEnum()) { try { result = Enum.valueOf((Class) converterClass, value.toUpperCase()); } catch (Exception e) { -- cgit v1.2.3 From d5490aabc6002f9400e5cf3050f098ab967253d2 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 10 Nov 2012 10:29:37 -0800 Subject: Fixed: GITHUB-107: Allow enum values without converting them to uppercase. --- src/main/java/com/beust/jcommander/JCommander.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index efde39e..4f2929e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1263,7 +1263,10 @@ public class JCommander { String optionName = names.length > 0 ? names[0] : "[Main class]"; if (converterClass != null && converterClass.isEnum()) { try { - result = Enum.valueOf((Class) converterClass, value.toUpperCase()); + result = Enum.valueOf((Class) converterClass, value); + if (result == null) { + result = Enum.valueOf((Class) converterClass, value.toUpperCase()); + } } catch (Exception e) { throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" + EnumSet.allOf((Class) converterClass)); -- cgit v1.2.3 From 07e332d70768d2f49d835ccf65628d73d2d6703f Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sat, 10 Nov 2012 11:30:30 -0800 Subject: Fixed: GITHUB-137: Main parameters with a default value should be overridden if a main parameter is specified --- src/main/java/com/beust/jcommander/JCommander.java | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 4f2929e..1bc0084 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -75,6 +75,8 @@ public class JCommander { */ private List m_objects = Lists.newArrayList(); + private boolean m_firstTimeMainParameter = true; + /** * This field/method will contain whatever command line parameter is not an option. * It is expected to be a List. @@ -913,6 +915,10 @@ public class JCommander { } m_mainParameter.set(m_mainParameterObject, result); } + if (m_firstTimeMainParameter) { + result.clear(); + m_firstTimeMainParameter = false; + } return result; } @@ -1241,21 +1247,6 @@ public class JCommander { } } - // -// // -// // Try to find a converter in the factory -// // -// IStringConverter converter = null; -// if (converterClass == null && m_converterFactories != null) { -// // Mmmh, javac requires a cast here -// converter = (IStringConverter) m_converterFactories.getConverter(type); -// } - -// if (converterClass == null) { -// throw new ParameterException("Don't know how to convert " + value -// + " to type " + type + " (field: " + field.getName() + ")"); -// } - IStringConverter converter; Object result = null; try { -- cgit v1.2.3 From 74678a3a186b681f116c1580d6c3445a03207039 Mon Sep 17 00:00:00 2001 From: kjpoalses Date: Fri, 21 Dec 2012 08:04:51 +0000 Subject: New: @Parameters can now be used with cglib proxies --- src/main/java/com/beust/jcommander/Parameters.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index be5b5ce..9834ea0 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -18,11 +18,12 @@ package com.beust.jcommander; -import static java.lang.annotation.ElementType.TYPE; - +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.TYPE; + /** * An annotation used to specify settings for parameter parsing. * @@ -30,6 +31,7 @@ import java.lang.annotation.Target; */ @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({ TYPE }) +@Inherited public @interface Parameters { public static final String DEFAULT_OPTION_PREFIXES = "-"; -- cgit v1.2.3 From b2435441a8c891f9577fdab4421a580f5f807758 Mon Sep 17 00:00:00 2001 From: Mike Drob Date: Fri, 7 Jun 2013 03:04:36 -0400 Subject: bugfix to address quoted main params --- src/main/java/com/beust/jcommander/JCommander.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 1bc0084..b78d890 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -680,6 +680,7 @@ public class JCommander { while (i < args.length && ! commandParsed) { String arg = args[i]; String a = trim(arg); + args[i] = a; p("Parsing arg: " + a); JCommander jc = findCommandByAlias(arg); @@ -748,7 +749,7 @@ public class JCommander { // Regular (non-command) parsing // List mp = getMainParameter(arg); - String value = arg; + String value = a; // If there's a non-quoted version, prefer that one Object convertedValue = value; if (m_mainParameter.getGenericType() instanceof ParameterizedType) { -- cgit v1.2.3 From d627b357c2a63b003869de40221c02b04d0eb663 Mon Sep 17 00:00:00 2001 From: Julien Massenet Date: Mon, 5 Aug 2013 14:41:43 +0200 Subject: Do not close System.in when using DefaultConsole --- src/main/java/com/beust/jcommander/internal/DefaultConsole.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java index 65e87ba..8fd7d6d 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java @@ -18,11 +18,10 @@ public class DefaultConsole implements Console { public char[] readPassword(boolean echoInput) { try { + // Do not close the readers since System.in should not be closed InputStreamReader isr = new InputStreamReader(System.in); BufferedReader in = new BufferedReader(isr); String result = in.readLine(); - in.close(); - isr.close(); return result.toCharArray(); } catch (IOException e) { -- cgit v1.2.3 From 04e646fe260cced3e41c20c7807a7af7207ea32f Mon Sep 17 00:00:00 2001 From: Andy Law Date: Mon, 17 Feb 2014 11:40:19 +0000 Subject: Fixed problem whereby Parameters returning Lists and with alternate names were being reset on the first use of an alternate name. Added test to ensure correct behaviour. --- src/main/java/com/beust/jcommander/JCommander.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index b78d890..a763bc1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -544,13 +544,13 @@ public class JCommander { m_mainParameterDescription = new ParameterDescription(object, p, parameterized, m_bundle, this); } else { + ParameterDescription pd = + new ParameterDescription(object, p, parameterized, m_bundle, this); for (String name : p.names()) { if (m_descriptions.containsKey(new StringKey(name))) { throw new ParameterException("Found the option " + name + " multiple times"); } p("Adding description for " + name); - ParameterDescription pd = - new ParameterDescription(object, p, parameterized, m_bundle, this); m_fields.put(parameterized, pd); m_descriptions.put(new StringKey(name), pd); -- cgit v1.2.3 From aa87f5891a77dffdf24bc4fb1f766ec976b064c1 Mon Sep 17 00:00:00 2001 From: Yannick Menager Date: Thu, 27 Feb 2014 14:22:28 +0000 Subject: Fixes #184 Bug in enum parsing --- src/main/java/com/beust/jcommander/JCommander.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index a763bc1..08efd8b 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1256,9 +1256,8 @@ public class JCommander { if (converterClass != null && converterClass.isEnum()) { try { result = Enum.valueOf((Class) converterClass, value); - if (result == null) { - result = Enum.valueOf((Class) converterClass, value.toUpperCase()); - } + } catch ( IllegalArgumentException e ) { + result = Enum.valueOf((Class) converterClass, value.toUpperCase()); } catch (Exception e) { throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" + EnumSet.allOf((Class) converterClass)); -- cgit v1.2.3 From 7c5bf86fc5d5e85d471e3722a39b7a21101b0484 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Mon, 7 Apr 2014 22:24:08 -0700 Subject: Support for "--". --- src/main/java/com/beust/jcommander/JCommander.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 08efd8b..3884976 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -685,7 +685,7 @@ public class JCommander { JCommander jc = findCommandByAlias(arg); int increment = 1; - if (isOption(args, a) && jc == null) { + if (! "--".equals(a) && isOption(args, a) && jc == null) { // // Option // @@ -744,6 +744,9 @@ public class JCommander { // Main parameter // if (! Strings.isStringEmpty(arg)) { + if ("--".equals(arg)) { + a = trim(args[++i]); + } if (m_commands.isEmpty()) { // // Regular (non-command) parsing -- cgit v1.2.3 From d9bec530f2d1c83289e8f325b33940cafce6b6c2 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sat, 17 May 2014 22:53:59 +0200 Subject: Added support for URL parameters --- .../beust/jcommander/converters/URLConverter.java | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/converters/URLConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/URLConverter.java b/src/main/java/com/beust/jcommander/converters/URLConverter.java new file mode 100644 index 0000000..1f3734b --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/URLConverter.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Convert a string into a URI. + * + * @author samvv + */ +public class URLConverter extends BaseConverter { + + public URLConverter(String optionName) { + super(optionName); + } + + public URL convert(String value) { + try { + return new URL(value); + } catch (MalformedURLException e) { + throw new ParameterException( + getErrorString(value, "a RFC 2396 and RFC 2732 compliant URL")); + + } + } +} \ No newline at end of file -- cgit v1.2.3 From 495398d07b80ba24b6a1eaff0f0c973d4a295dcc Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sat, 17 May 2014 22:57:11 +0200 Subject: Added support for URI parameters --- .../beust/jcommander/converters/URIConverter.java | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/converters/URIConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/URIConverter.java b/src/main/java/com/beust/jcommander/converters/URIConverter.java new file mode 100644 index 0000000..82f6ace --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/URIConverter.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.ParameterException; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Convert a string into a URI. + * + * @author samvv + */ +public class URIConverter extends BaseConverter { + + public URIConverter(String optionName) { + super(optionName); + } + + public URI convert(String value) { + try { + return new URI(value); + } catch (URISyntaxException e) { + throw new ParameterException( + getErrorString(value, "a RFC 2396 and RFC 2732 compliant URI")); + } + } + +} -- cgit v1.2.3 From 3899d473faed68a3d308336d213626dffaa030e7 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sat, 17 May 2014 22:58:37 +0200 Subject: Added support for Java NIO Paths --- .../beust/jcommander/converters/PathConverter.java | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/com/beust/jcommander/converters/PathConverter.java (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/PathConverter.java b/src/main/java/com/beust/jcommander/converters/PathConverter.java new file mode 100644 index 0000000..dcd5b43 --- /dev/null +++ b/src/main/java/com/beust/jcommander/converters/PathConverter.java @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2010 the original author or authors. + * See the notice.md file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.beust.jcommander.converters; + +import com.beust.jcommander.IStringConverter; + +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Convert a string into a path. + * + * @author samvv + */ +public class PathConverter implements IStringConverter { + + public Path convert(String value) { + return Paths.get(value); + } + +} -- cgit v1.2.3 From b55abbbe352028c09c37f0c37a9f4dfa099838b5 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sat, 17 May 2014 23:13:55 +0200 Subject: Aligned indentation with rest of the code --- .../beust/jcommander/converters/PathConverter.java | 4 ++-- .../beust/jcommander/converters/URIConverter.java | 27 +++++++++++----------- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/converters/PathConverter.java b/src/main/java/com/beust/jcommander/converters/PathConverter.java index dcd5b43..b7fdafd 100644 --- a/src/main/java/com/beust/jcommander/converters/PathConverter.java +++ b/src/main/java/com/beust/jcommander/converters/PathConverter.java @@ -29,9 +29,9 @@ import java.nio.file.Paths; * @author samvv */ public class PathConverter implements IStringConverter { - + public Path convert(String value) { return Paths.get(value); } - + } diff --git a/src/main/java/com/beust/jcommander/converters/URIConverter.java b/src/main/java/com/beust/jcommander/converters/URIConverter.java index 82f6ace..3473bf0 100644 --- a/src/main/java/com/beust/jcommander/converters/URIConverter.java +++ b/src/main/java/com/beust/jcommander/converters/URIConverter.java @@ -29,18 +29,17 @@ import java.net.URISyntaxException; * @author samvv */ public class URIConverter extends BaseConverter { - - public URIConverter(String optionName) { - super(optionName); - } - - public URI convert(String value) { - try { - return new URI(value); - } catch (URISyntaxException e) { - throw new ParameterException( - getErrorString(value, "a RFC 2396 and RFC 2732 compliant URI")); - } - } - + + public URIConverter(String optionName) { + super(optionName); + } + + public URI convert(String value) { + try { + return new URI(value); + } catch (URISyntaxException e) { + throw new ParameterException(getErrorString(value, "a RFC 2396 and RFC 2732 compliant URI")); + } + } + } -- cgit v1.2.3 From 44ef916dcf74e46adbf7c2ae99643bd0e97c16e6 Mon Sep 17 00:00:00 2001 From: John Conwell Date: Fri, 6 Jun 2014 19:00:27 -0700 Subject: Adding functionality that allows commands to be hidden from usage output --- src/main/java/com/beust/jcommander/JCommander.java | 18 +++++++++++------- src/main/java/com/beust/jcommander/Parameters.java | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3884976..5538661 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1119,13 +1119,17 @@ public class JCommander { // The magic value 3 is the number of spaces between the name of the option // and its description for (Map.Entry commands : m_commands.entrySet()) { - ProgramName progName = commands.getKey(); - String dispName = progName.getDisplayName(); - out.append(indent).append(" " + dispName); // + s(spaceCount) + getCommandDescription(progName.name) + "\n"); - - // Options for this command - usage(progName.getName(), out, " "); - out.append("\n"); + Object arg = commands.getValue().getObjects().get(0); + Parameters p = arg.getClass().getAnnotation(Parameters.class); + if (!p.hidden()) { + ProgramName progName = commands.getKey(); + String dispName = progName.getDisplayName(); + out.append(indent).append(" " + dispName); // + s(spaceCount) + getCommandDescription(progName.name) + "\n"); + + // Options for this command + usage(progName.getName(), out, " "); + out.append("\n"); + } } } } diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java index 9834ea0..f2e8c76 100644 --- a/src/main/java/com/beust/jcommander/Parameters.java +++ b/src/main/java/com/beust/jcommander/Parameters.java @@ -67,4 +67,9 @@ public @interface Parameters { * An array of allowed command names. */ String[] commandNames() default {}; + + /** + * If true, this command won't appear in the usage(). + */ + boolean hidden() default false; } -- cgit v1.2.3 From 55e9949641d8906e622ea92f40ac1138ae74a30c Mon Sep 17 00:00:00 2001 From: helllth Date: Tue, 22 Jul 2014 13:41:46 +0200 Subject: add the possibility to have # comments in a @file --- src/main/java/com/beust/jcommander/JCommander.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 3884976..f4a29e5 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -485,8 +485,10 @@ public class JCommander { // Read through file one line at time. Print line # and line while ((line = bufRead.readLine()) != null) { - // Allow empty lines in these at files - if (line.length() > 0) result.add(line); + // Allow empty lines and # comments in these at files + if (line.length() > 0 && ! line.trim().startsWith("#")) { + result.add(line); + } } bufRead.close(); -- cgit v1.2.3 From 9d7035d4d9145090a0d20869963e23014b835577 Mon Sep 17 00:00:00 2001 From: helllth Date: Tue, 22 Jul 2014 16:13:01 +0200 Subject: add possibility to allow parameter overwriting (and even disallowing it for certain parameters) --- src/main/java/com/beust/jcommander/JCommander.java | 7 +++++++ src/main/java/com/beust/jcommander/Parameter.java | 8 ++++++++ src/main/java/com/beust/jcommander/ParameterDescription.java | 6 +++++- src/main/java/com/beust/jcommander/WrappedParameter.java | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index f4a29e5..04f98ba 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -154,6 +154,7 @@ public class JCommander { private List m_unknownArgs = Lists.newArrayList(); private boolean m_acceptUnknownOptions = false; + private boolean m_allowParameterOverwriting = false; private static Console m_console; @@ -1567,7 +1568,13 @@ public class JCommander { public List getUnknownOptions() { return m_unknownArgs; } + public void setAllowParameterOverwriting(boolean b) { + m_allowParameterOverwriting = b; + } + public boolean isParameterOverwritingAllowed() { + return m_allowParameterOverwriting; + } // public void setCaseSensitiveCommands(boolean b) { // m_caseSensitiveCommands = b; // } diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java index 974eeaa..d8cf87d 100644 --- a/src/main/java/com/beust/jcommander/Parameter.java +++ b/src/main/java/com/beust/jcommander/Parameter.java @@ -119,4 +119,12 @@ public @interface Parameter { * required parameters are no longer checked for their presence. */ boolean help() default false; + + /** + * If true, this parameter can be overwritten through a file or another appearance of the parameter + * @return + */ + boolean forceNonOverwritable() default false; + + } diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index 33574a9..e41c782 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -231,7 +231,7 @@ public class ParameterDescription { p("Adding " + (isDefault ? "default " : "") + "value:" + value + " to parameter:" + m_parameterized.getName()); String name = m_wrappedParameter.names()[0]; - if (m_assigned && ! isMultiOption()) { + if (m_assigned && ! isMultiOption() && !m_jCommander.isParameterOverwritingAllowed() || isNonOverwritableForced()) { throw new ParameterException("Can only specify option " + name + " once."); } @@ -358,4 +358,8 @@ public class ParameterDescription { public boolean isHelp() { return m_wrappedParameter.isHelp(); } + + public boolean isNonOverwritableForced() { + return m_wrappedParameter.isNonOverwritableForced(); + } } diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java index 52cafc4..f4e7d56 100644 --- a/src/main/java/com/beust/jcommander/WrappedParameter.java +++ b/src/main/java/com/beust/jcommander/WrappedParameter.java @@ -109,4 +109,7 @@ public class WrappedParameter { return m_parameter != null && m_parameter.help(); } + public boolean isNonOverwritableForced() { + return m_parameter != null && m_parameter.forceNonOverwritable(); + } } -- cgit v1.2.3 From 84d37323ff2416cf9a98dd96fab25f52eed1b516 Mon Sep 17 00:00:00 2001 From: chilinglam Date: Fri, 12 Sep 2014 13:58:23 -0400 Subject: propagate m_acceptUnknownOptions to addCommand --- src/main/java/com/beust/jcommander/JCommander.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index ecbb1cd..7f6638a 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1371,6 +1371,7 @@ public class JCommander { JCommander jc = new JCommander(object); jc.setProgramName(name, aliases); jc.setDefaultProvider(m_defaultProvider); + jc.setAcceptUnknownOptions(m_acceptUnknownOptions); ProgramName progName = jc.m_programName; m_commands.put(progName, jc); -- cgit v1.2.3 From e217da3bb340b5a319b79025fbb09f6207e5c3a2 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 14 Sep 2014 09:55:37 -0700 Subject: Fix --. --- src/main/java/com/beust/jcommander/JCommander.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 7f6638a..53246b3 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -680,6 +680,7 @@ public class JCommander { // object) boolean commandParsed = false; int i = 0; + boolean isDashDash = false; // once we encounter --, everything goes into the main parameter while (i < args.length && ! commandParsed) { String arg = args[i]; String a = trim(arg); @@ -688,7 +689,7 @@ public class JCommander { JCommander jc = findCommandByAlias(arg); int increment = 1; - if (! "--".equals(a) && isOption(args, a) && jc == null) { + if (! isDashDash && ! "--".equals(a) && isOption(args, a) && jc == null) { // // Option // @@ -748,6 +749,7 @@ public class JCommander { // if (! Strings.isStringEmpty(arg)) { if ("--".equals(arg)) { + isDashDash = true; a = trim(args[++i]); } if (m_commands.isEmpty()) { -- cgit v1.2.3 From 460b51f6319bb8b8c621fce06346eaab7902c9b8 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Sun, 14 Sep 2014 10:01:36 -0700 Subject: Fix enumArgsFail. --- src/main/java/com/beust/jcommander/JCommander.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 53246b3..98f112e 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1268,11 +1268,16 @@ public class JCommander { if (converterClass != null && converterClass.isEnum()) { try { result = Enum.valueOf((Class) converterClass, value); - } catch ( IllegalArgumentException e ) { - result = Enum.valueOf((Class) converterClass, value.toUpperCase()); + } catch (IllegalArgumentException e) { + try { + result = Enum.valueOf((Class) converterClass, value.toUpperCase()); + } catch (IllegalArgumentException ex) { + throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" + + EnumSet.allOf((Class) converterClass)); + } } catch (Exception e) { throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" + - EnumSet.allOf((Class) converterClass)); + EnumSet.allOf((Class) converterClass)); } } else { converter = instantiateConverter(optionName, converterClass); -- cgit v1.2.3 From fb7a1a73d02a75e62b85e86e8b592af57733a36e Mon Sep 17 00:00:00 2001 From: Manuel Boillod Date: Sun, 16 Nov 2014 16:24:27 +0100 Subject: fix for issue200 Incorrect usage() formatting with single long options --- src/main/java/com/beust/jcommander/ParameterDescription.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java index e41c782..2ef2d5f 100644 --- a/src/main/java/com/beust/jcommander/ParameterDescription.java +++ b/src/main/java/com/beust/jcommander/ParameterDescription.java @@ -186,7 +186,6 @@ public class ParameterDescription { String[] names = m_wrappedParameter.names(); for (int i = 0; i < names.length; i++) { if (i > 0) sb.append(", "); - if (names.length == 1 && names[i].startsWith("--")) sb.append(" "); sb.append(names[i]); } return sb.toString(); -- cgit v1.2.3 From 495a006cacb2a62449b74474fc57ca2e1b37d85d Mon Sep 17 00:00:00 2001 From: TKlerx Date: Fri, 13 Mar 2015 10:01:51 +0100 Subject: Added default converters for Path, URI and URL --- .../com/beust/jcommander/internal/DefaultConverterFactory.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java index f98a111..2b8a10c 100644 --- a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java +++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java @@ -29,10 +29,16 @@ import com.beust.jcommander.converters.ISO8601DateConverter; import com.beust.jcommander.converters.IntegerConverter; import com.beust.jcommander.converters.LongConverter; import com.beust.jcommander.converters.StringConverter; +import com.beust.jcommander.converters.PathConverter; +import com.beust.jcommander.converters.URIConverter; +import com.beust.jcommander.converters.URLConverter; import java.io.File; import java.math.BigDecimal; import java.util.Date; +import java.net.URI; +import java.net.URL; +import java.nio.file.Path; import java.util.Map; public class DefaultConverterFactory implements IStringConverterFactory { @@ -57,6 +63,9 @@ public class DefaultConverterFactory implements IStringConverterFactory { m_classConverters.put(File.class, FileConverter.class); m_classConverters.put(BigDecimal.class, BigDecimalConverter.class); m_classConverters.put(Date.class, ISO8601DateConverter.class); + m_classConverters.put(Path.class, PathConverter.class); + m_classConverters.put(URI.class, URIConverter.class); + m_classConverters.put(URL.class, URLConverter.class); } public Class> getConverter(Class forType) { -- cgit v1.2.3 From cea0c1642b084285d232968a701086267b4b3ec3 Mon Sep 17 00:00:00 2001 From: TKlerx Date: Fri, 13 Mar 2015 10:08:50 +0100 Subject: Added enum constants to usage output --- src/main/java/com/beust/jcommander/JCommander.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java index 98f112e..2e049a1 100644 --- a/src/main/java/com/beust/jcommander/JCommander.java +++ b/src/main/java/com/beust/jcommander/JCommander.java @@ -1113,6 +1113,11 @@ public class JCommander { out.append("\n" + s(indentCount + 1)) .append("Default: " + (parameter.password()?"********" : displayedDef)); } + Class type = pd.getParameterized().getType(); + if(type.isEnum()){ + out.append("\n" + s(indentCount + 1)) + .append("Possible Values: " + EnumSet.allOf((Class) type)); + } out.append("\n"); } -- cgit v1.2.3 From e47fce5f08c9fc1214253d2bc4679da059d649b9 Mon Sep 17 00:00:00 2001 From: Nikolay Martynov Date: Thu, 9 Apr 2015 17:03:48 -0400 Subject: Allow users to create ParameterException with description and cause This is useful in custom validators: it may want to provide both description and exception caused it. E.g. in case of file operations --- src/main/java/com/beust/jcommander/ParameterException.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/main/java/com/beust') diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java index 3c0f588..2bba7d1 100644 --- a/src/main/java/com/beust/jcommander/ParameterException.java +++ b/src/main/java/com/beust/jcommander/ParameterException.java @@ -34,5 +34,9 @@ public class ParameterException extends RuntimeException { public ParameterException(String string) { super(string); } + + public ParameterException(String string, Throwable t) { + super(string, t); + } } -- cgit v1.2.3