private static <T> T convertFrom(Object x, OpenType<T> openType) {
   if (openType.isValue(x)) {
     T t = OpenMBeanAttributeInfoSupport.<T>cast(x);
     return t;
   }
   return convertFromStrings(x, openType);
 }
  /**
   * Returns the hash code value for this {@code OpenMBeanParameterInfoSupport} instance.
   *
   * <p>The hash code of an {@code OpenMBeanParameterInfoSupport} instance is the sum of the hash
   * codes of all elements of information used in {@code equals} comparisons (ie: its name, its
   * <i>open type</i>, its default, min, max and legal values, and its Descriptor).
   *
   * <p>This ensures that {@code t1.equals(t2)} implies that {@code t1.hashCode()==t2.hashCode()}
   * for any two {@code OpenMBeanParameterInfoSupport} instances {@code t1} and {@code t2}, as
   * required by the general contract of the method {@link Object#hashCode() Object.hashCode()}.
   *
   * <p>However, note that another instance of a class implementing the {@code
   * OpenMBeanParameterInfo} interface may be equal to this {@code OpenMBeanParameterInfoSupport}
   * instance as defined by {@link #equals(java.lang.Object)}, but may have a different hash code if
   * it is calculated differently.
   *
   * <p>As {@code OpenMBeanParameterInfoSupport} instances are immutable, the hash code for this
   * instance is calculated once, on the first call to {@code hashCode}, and then the same value is
   * returned for subsequent calls.
   *
   * @return the hash code value for this {@code OpenMBeanParameterInfoSupport} instance
   */
  public int hashCode() {

    // Calculate the hash code value if it has not yet been done
    // (ie 1st call to hashCode())
    //
    if (myHashCode == null) myHashCode = OpenMBeanAttributeInfoSupport.hashCode(this);

    // return always the same hash code for this instance (immutable)
    //
    return myHashCode.intValue();
  }
  /**
   * Returns a string representation of this {@code OpenMBeanParameterInfoSupport} instance.
   *
   * <p>The string representation consists of the name of this class (i.e. {@code
   * javax.management.openmbean.OpenMBeanParameterInfoSupport}), the string representation of the
   * name and open type of the described parameter, the string representation of its default, min,
   * max and legal values and the string representation of its descriptor.
   *
   * <p>As {@code OpenMBeanParameterInfoSupport} instances are immutable, the string representation
   * for this instance is calculated once, on the first call to {@code toString}, and then the same
   * value is returned for subsequent calls.
   *
   * @return a string representation of this {@code OpenMBeanParameterInfoSupport} instance.
   */
  public String toString() {

    // Calculate the string value if it has not yet been done (ie
    // 1st call to toString())
    //
    if (myToString == null) myToString = OpenMBeanAttributeInfoSupport.toString(this);

    // return always the same string representation for this
    // instance (immutable)
    //
    return myToString;
  }
 /* 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);
 }
 /**
  * Tests whether {@code obj} is a valid value for the parameter described by this {@code
  * OpenMBeanParameterInfo} instance.
  *
  * @param obj the object to be tested.
  * @return {@code true} if {@code obj} is a valid value for the parameter described by this {@code
  *     OpenMBeanParameterInfo} instance, {@code false} otherwise.
  */
 public boolean isValue(Object obj) {
   return OpenMBeanAttributeInfoSupport.isValue(this, obj);
   // compiler bug? should be able to omit class name here
   // also below in toString and hashCode
 }