summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/beust/jcommander/ParameterDescription.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/beust/jcommander/ParameterDescription.java')
-rw-r--r--src/main/java/com/beust/jcommander/ParameterDescription.java364
1 files changed, 364 insertions, 0 deletions
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..2ef2d5f
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParameterDescription.java
@@ -0,0 +1,364 @@
+/**
+ * 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.validators.NoValidator;
+import com.beust.jcommander.validators.NoValueValidator;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+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;
+import java.util.TreeSet;
+
+public class ParameterDescription {
+ private Object m_object;
+
+ private WrappedParameter m_wrappedParameter;
+ private Parameter m_parameterAnnotation;
+ private DynamicParameter m_dynamicParameterAnnotation;
+
+ /** 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;
+ 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, DynamicParameter annotation,
+ Parameterized parameterized,
+ ResourceBundle bundle, JCommander jc) {
+ 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, parameterized, bundle, jc);
+ }
+
+ public ParameterDescription(Object object, Parameter annotation, Parameterized parameterized,
+ ResourceBundle bundle, JCommander jc) {
+ m_parameterAnnotation = annotation;
+ m_wrappedParameter = new WrappedParameter(m_parameterAnnotation);
+ init(object, parameterized, bundle, jc);
+ }
+
+ /**
+ * Find the resource bundle in the annotations.
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ private ResourceBundle findResourceBundle(Object o) {
+ ResourceBundle result = null;
+
+ Parameters p = o.getClass().getAnnotation(Parameters.class);
+ if (p != null && ! isEmpty(p.resourceBundle())) {
+ result = ResourceBundle.getBundle(p.resourceBundle(), Locale.getDefault());
+ } else {
+ com.beust.jcommander.ResourceBundle a = o.getClass().getAnnotation(
+ com.beust.jcommander.ResourceBundle.class);
+ if (a != null && ! isEmpty(a.value())) {
+ result = ResourceBundle.getBundle(a.value(), Locale.getDefault());
+ }
+ }
+
+ return result;
+ }
+
+ private boolean isEmpty(String s) {
+ return s == null || "".equals(s);
+ }
+
+ private void initDescription(String description, String descriptionKey, String[] names) {
+ m_description = description;
+ if (! "".equals(descriptionKey)) {
+ if (m_bundle != null) {
+ 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 " +
+// "default description:'" + m_description + "'");
+ }
+ }
+
+ for (String name : names) {
+ if (name.length() > m_longestName.length()) m_longestName = name;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void init(Object object, Parameterized parameterized, ResourceBundle bundle,
+ JCommander jCommander) {
+ m_object = object;
+ m_parameterized = parameterized;
+ m_bundle = bundle;
+ if (m_bundle == null) {
+ m_bundle = findResourceBundle(object);
+ }
+ m_jCommander = jCommander;
+
+ if (m_parameterAnnotation != null) {
+ String description;
+ if (Enum.class.isAssignableFrom(parameterized.getType())
+ && m_parameterAnnotation.description().isEmpty()) {
+ description = "Options: " + EnumSet.allOf((Class<? extends Enum>) parameterized.getType());
+ }else {
+ description = m_parameterAnnotation.description();
+ }
+ initDescription(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 = parameterized.get(object);
+ } catch (Exception e) {
+ }
+
+ //
+ // Validate default values, if any and if applicable
+ //
+ if (m_default != null) {
+ if (m_parameterAnnotation != null) {
+ validateDefaultValues(m_parameterAnnotation.names());
+ }
+ }
+ }
+
+ private void validateDefaultValues(String[] names) {
+ String name = names.length > 0 ? names[0] : "";
+ validateValueParameter(name, m_default);
+ }
+
+ public String getLongestName() {
+ return m_longestName;
+ }
+
+ public Object getDefault() {
+ return m_default;
+ }
+
+ public String getDescription() {
+ return m_description;
+ }
+
+ public Object getObject() {
+ return m_object;
+ }
+
+ public String getNames() {
+ StringBuilder sb = new StringBuilder();
+ String[] names = m_wrappedParameter.names();
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) sb.append(", ");
+ sb.append(names[i]);
+ }
+ return sb.toString();
+ }
+
+ public WrappedParameter getParameter() {
+ return m_wrappedParameter;
+ }
+
+ public Parameterized getParameterized() {
+ return m_parameterized;
+ }
+
+ private boolean isMultiOption() {
+ Class<?> fieldType = m_parameterized.getType();
+ return fieldType.equals(List.class) || fieldType.equals(Set.class)
+ || m_parameterized.isDynamicParameter();
+ }
+
+ public void addValue(String value) {
+ addValue(value, false /* not default */);
+ }
+
+ /**
+ * @return true if this parameter received a value during the parsing phase.
+ */
+ public boolean isAssigned() {
+ return m_assigned;
+ }
+
+
+ public void setAssigned(boolean b) {
+ m_assigned = b;
+ }
+
+ /**
+ * 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_parameterized.getName());
+ String name = m_wrappedParameter.names()[0];
+ if (m_assigned && ! isMultiOption() && !m_jCommander.isParameterOverwritingAllowed() || isNonOverwritableForced()) {
+ throw new ParameterException("Can only specify option " + name + " once.");
+ }
+
+ validateParameter(name, value);
+
+ Class<?> type = m_parameterized.getType();
+
+ Object convertedValue = m_jCommander.convertValue(this, value);
+ validateValueParameter(name, convertedValue);
+ boolean isCollection = Collection.class.isAssignableFrom(type);
+
+ if (isCollection) {
+ @SuppressWarnings("unchecked")
+ Collection<Object> l = (Collection<Object>) 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_parameterized, m_object, convertedValue);
+ }
+ if (! isDefault) m_assigned = true;
+ }
+
+ private void validateParameter(String name, String value) {
+ Class<? extends IParameterValidator> validator = m_wrappedParameter.validateWith();
+ if (validator != null) {
+ validateParameter(this, validator, name, value);
+ }
+ }
+
+ private void validateValueParameter(String name, Object value) {
+ Class<? extends IValueValidator> validator = m_wrappedParameter.validateValueWith();
+ if (validator != null) {
+ validateValueParameter(validator, name, value);
+ }
+ }
+
+ public static void validateValueParameter(Class<? extends IValueValidator> 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(ParameterDescription pd,
+ Class<? extends IParameterValidator> 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) {
+ throw new ParameterException("Can't instantiate validator:" + e);
+ } catch(ParameterException ex) {
+ throw ex;
+ } catch(Exception ex) {
+ throw new ParameterException(ex);
+ }
+ }
+
+ /*
+ * Creates a new collection for the field's type.
+ *
+ * Currently only List and Set are supported. Support for
+ * Queues and Stacks could be useful.
+ */
+ @SuppressWarnings("unchecked")
+ private Collection<Object> 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()
+ + "' 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);
+ }
+
+ private static void p(String string) {
+ if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) {
+ JCommander.getConsole().println("[ParameterDescription] " + string);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[ParameterDescription " + m_parameterized.getName() + "]";
+ }
+
+ public boolean isDynamicParameter() {
+ return m_dynamicParameterAnnotation != null;
+ }
+
+ public boolean isHelp() {
+ return m_wrappedParameter.isHelp();
+ }
+
+ public boolean isNonOverwritableForced() {
+ return m_wrappedParameter.isNonOverwritableForced();
+ }
+}