/**
   * Constructs an {@code OpenMBeanParameterInfoSupport} instance, which describes the parameter
   * used in one or more operations or constructors of a class of open MBeans, with the specified
   * {@code name}, {@code openType}, {@code description}, and {@code descriptor}.
   *
   * <p>The {@code descriptor} can contain entries that will define the values returned by certain
   * methods of this class, as explained in the {@link <a href="package-summary.html#constraints">
   * package description</a>}.
   *
   * @param name cannot be a null or empty string.
   * @param description cannot be a null or empty string.
   * @param openType cannot be null.
   * @param descriptor The descriptor for the parameter. This may be null which is equivalent to an
   *     empty descriptor.
   * @throws IllegalArgumentException if {@code name} or {@code description} are null or empty
   *     string, or {@code openType} is null, or the descriptor entries are invalid as described in
   *     the {@link <a href="package-summary.html#constraints">package description</a>}.
   * @since 1.6
   */
  public OpenMBeanParameterInfoSupport(
      String name, String description, OpenType<?> openType, Descriptor descriptor) {

    // Construct parent's state
    //
    super(
        name,
        (openType == null) ? null : openType.getClassName(),
        description,
        ImmutableDescriptor.union(
            descriptor, (openType == null) ? null : openType.getDescriptor()));

    // Initialize this instance's specific state
    //
    this.openType = openType;

    descriptor = getDescriptor(); // replace null by empty
    this.defaultValue = valueFrom(descriptor, "defaultValue", openType);
    this.legalValues = valuesFrom(descriptor, "legalValues", openType);
    this.minValue = comparableValueFrom(descriptor, "minValue", openType);
    this.maxValue = comparableValueFrom(descriptor, "maxValue", openType);

    try {
      check(this);
    } catch (OpenDataException e) {
      throw new IllegalArgumentException(e.getMessage(), e);
    }
  }
 /* A Descriptor contained an array value encoded as Strings.  The
 Strings must be organized in an array corresponding to the desired
 array.  If the desired array has n dimensions, so must the String
 array.  We will convert element by element from String to desired
 component type. */
 private static <T> T convertFromStringArray(Object x, OpenType<T> openType) {
   ArrayType<?> arrayType = (ArrayType<?>) openType;
   OpenType<?> baseType = arrayType.getElementOpenType();
   int dim = arrayType.getDimension();
   String squareBrackets = "[";
   for (int i = 1; i < dim; i++) squareBrackets += "[";
   Class<?> stringArrayClass;
   Class<?> targetArrayClass;
   try {
     stringArrayClass = Class.forName(squareBrackets + "Ljava.lang.String;");
     targetArrayClass = Class.forName(squareBrackets + "L" + baseType.safeGetClassName() + ";");
   } catch (ClassNotFoundException e) {
     throw new NoClassDefFoundError(e.toString()); // can't happen
   }
   if (!stringArrayClass.isInstance(x)) {
     final String msg =
         "Value for "
             + dim
             + "-dimensional array of "
             + baseType.getTypeName()
             + " must be same type or a String "
             + "array with same dimensions";
     throw new IllegalArgumentException(msg);
   }
   OpenType<?> componentOpenType;
   if (dim == 1) componentOpenType = baseType;
   else {
     try {
       componentOpenType = new ArrayType<T>(dim - 1, baseType);
     } catch (OpenDataException e) {
       throw new IllegalArgumentException(e.getMessage(), e);
       // can't happen
     }
   }
   int n = Array.getLength(x);
   Object[] targetArray = (Object[]) Array.newInstance(targetArrayClass.getComponentType(), n);
   for (int i = 0; i < n; i++) {
     Object stringish = Array.get(x, i); // String or String[] etc
     Object converted = convertFromStrings(stringish, componentOpenType);
     Array.set(targetArray, i, converted);
   }
   return OpenMBeanAttributeInfoSupport.<T>cast(targetArray);
 }