12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.management.openmbean;
27
28 import java.io.ObjectStreamException;
29 import java.lang.reflect.Array;
30
31 /**
32 * The <code>ArrayType</code> class is the <i>open type</i> class whose instances describe
33 * all <i>open data</i> values which are n-dimensional arrays of <i>open data</i> values.
34 * <p>
35 * Examples of valid {@code ArrayType} instances are:
36 * <pre>{@code
37 * // 2-dimension array of java.lang.String
38 * ArrayType<String[][]> a1 = new ArrayType<String[][]>(2, SimpleType.STRING);
39 *
40 * // 1-dimension array of int
41 * ArrayType<int[]> a2 = new ArrayType<int[]>(SimpleType.INTEGER, true);
42 *
43 * // 1-dimension array of java.lang.Integer
44 * ArrayType<Integer[]> a3 = new ArrayType<Integer[]>(SimpleType.INTEGER, false);
45 *
46 * // 4-dimension array of int
47 * ArrayType<int[][][][]> a4 = new ArrayType<int[][][][]>(3, a2);
48 *
49 * // 4-dimension array of java.lang.Integer
50 * ArrayType<Integer[][][][]> a5 = new ArrayType<Integer[][][][]>(3, a3);
51 *
52 * // 1-dimension array of java.lang.String
205 * e.g. SimpleType.BOOLEAN for "boolean", SimpleType.CHARACTER for
206 * "char", etc...
207 * @param primitiveTypeName the primitive type of the array element ("boolean",
208 * "char", etc...)
209 * @return the OpenType corresponding to the given primitive type name
210 * (SimpleType.BOOLEAN, SimpleType.CHARACTER, etc...)
211 * return null if the given elementClassName is not a primitive
212 * type name.
213 **/
214 static SimpleType<?> getPrimitiveOpenType(String primitiveTypeName) {
215 for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
216 if (primitiveTypeName.equals(typeDescr[PRIMITIVE_TYPE_NAME_INDEX]))
217 return (SimpleType<?>)typeDescr[PRIMITIVE_OPEN_TYPE_INDEX];
218 }
219 return null;
220 }
221
222 /* *** Constructor *** */
223
224 /**
225 * Constructs an <tt>ArrayType</tt> instance describing <i>open data</i> values which are
226 * arrays with dimension <var>dimension</var> of elements whose <i>open type</i> is <var>elementType</var>.
227 * <p>
228 * When invoked on an <tt>ArrayType</tt> instance, the {@link OpenType#getClassName() getClassName} method
229 * returns the class name of the array instances it describes (following the rules defined by the
230 * {@link Class#getName() getName} method of <code>java.lang.Class</code>), not the class name of the array elements
231 * (which is returned by a call to <tt>getElementOpenType().getClassName()</tt>).
232 * <p>
233 * The internal field corresponding to the type name of this <code>ArrayType</code> instance is also set to
234 * the class name of the array instances it describes.
235 * In other words, the methods <code>getClassName</code> and <code>getTypeName</code> return the same string value.
236 * The internal field corresponding to the description of this <code>ArrayType</code> instance is set to a string value
237 * which follows the following template:
238 * <ul>
239 * <li>if non-primitive array: <tt><i><dimension></i>-dimension array of <i><element_class_name></i></tt></li>
240 * <li>if primitive array: <tt><i><dimension></i>-dimension array of <i><primitive_type_of_the_element_class_name></i></tt></li>
241 * </ul>
242 * <p>
243 * As an example, the following piece of code:
244 * <pre>{@code
245 * ArrayType<String[][][]> t = new ArrayType<String[][][]>(3, SimpleType.STRING);
246 * System.out.println("array class name = " + t.getClassName());
247 * System.out.println("element class name = " + t.getElementOpenType().getClassName());
248 * System.out.println("array type name = " + t.getTypeName());
249 * System.out.println("array type description = " + t.getDescription());
250 * }</pre>
251 * would produce the following output:
252 * <pre>{@code
253 * array class name = [[[Ljava.lang.String;
254 * element class name = java.lang.String
255 * array type name = [[[Ljava.lang.String;
256 * array type description = 3-dimension array of java.lang.String
257 * }</pre>
258 * And the following piece of code which is equivalent to the one listed
259 * above would also produce the same output:
260 * <pre>{@code
261 * ArrayType<String[]> t1 = new ArrayType<String[]>(1, SimpleType.STRING);
262 * ArrayType<String[][]> t2 = new ArrayType<String[][]>(1, t1);
263 * ArrayType<String[][][]> t3 = new ArrayType<String[][][]>(1, t2);
264 * System.out.println("array class name = " + t3.getClassName());
265 * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
266 * System.out.println("array type name = " + t3.getTypeName());
267 * System.out.println("array type description = " + t3.getDescription());
268 * }</pre>
269 *
270 * @param dimension the dimension of arrays described by this <tt>ArrayType</tt> instance;
271 * must be greater than or equal to 1.
272 *
273 * @param elementType the <i>open type</i> of element values contained
274 * in the arrays described by this <tt>ArrayType</tt>
275 * instance; must be an instance of either
276 * <tt>SimpleType</tt>, <tt>CompositeType</tt>,
277 * <tt>TabularType</tt> or another <tt>ArrayType</tt>
278 * with a <tt>SimpleType</tt>, <tt>CompositeType</tt>
279 * or <tt>TabularType</tt> as its <tt>elementType</tt>.
280 *
281 * @throws IllegalArgumentException if {@code dimension} is not a positive
282 * integer.
283 * @throws OpenDataException if <var>elementType's className</var> is not
284 * one of the allowed Java class names for open
285 * data.
286 */
287 public ArrayType(int dimension,
288 OpenType<?> elementType) throws OpenDataException {
289 // Check and construct state defined by parent.
290 // We can't use the package-private OpenType constructor because
291 // we don't know if the elementType parameter is sane.
292 super(buildArrayClassName(dimension, elementType),
293 buildArrayClassName(dimension, elementType),
294 buildArrayDescription(dimension, elementType));
295
296 // Check and construct state specific to ArrayType
297 //
298 if (elementType.isArray()) {
299 ArrayType<?> at = (ArrayType<?>) elementType;
301 this.elementType = at.getElementOpenType();
302 this.primitiveArray = at.isPrimitiveArray();
303 } else {
304 this.dimension = dimension;
305 this.elementType = elementType;
306 this.primitiveArray = false;
307 }
308 }
309
310 /**
311 * Constructs a unidimensional {@code ArrayType} instance for the
312 * supplied {@code SimpleType}.
313 * <p>
314 * This constructor supports the creation of arrays of primitive
315 * types when {@code primitiveArray} is {@code true}.
316 * <p>
317 * For primitive arrays the {@link #getElementOpenType()} method
318 * returns the {@link SimpleType} corresponding to the wrapper
319 * type of the primitive type of the array.
320 * <p>
321 * When invoked on an <tt>ArrayType</tt> instance, the {@link OpenType#getClassName() getClassName} method
322 * returns the class name of the array instances it describes (following the rules defined by the
323 * {@link Class#getName() getName} method of <code>java.lang.Class</code>), not the class name of the array elements
324 * (which is returned by a call to <tt>getElementOpenType().getClassName()</tt>).
325 * <p>
326 * The internal field corresponding to the type name of this <code>ArrayType</code> instance is also set to
327 * the class name of the array instances it describes.
328 * In other words, the methods <code>getClassName</code> and <code>getTypeName</code> return the same string value.
329 * The internal field corresponding to the description of this <code>ArrayType</code> instance is set to a string value
330 * which follows the following template:
331 * <ul>
332 * <li>if non-primitive array: <tt>1-dimension array of <i><element_class_name></i></tt></li>
333 * <li>if primitive array: <tt>1-dimension array of <i><primitive_type_of_the_element_class_name></i></tt></li>
334 * </ul>
335 * <p>
336 * As an example, the following piece of code:
337 * <pre>{@code
338 * ArrayType<int[]> t = new ArrayType<int[]>(SimpleType.INTEGER, true);
339 * System.out.println("array class name = " + t.getClassName());
340 * System.out.println("element class name = " + t.getElementOpenType().getClassName());
341 * System.out.println("array type name = " + t.getTypeName());
342 * System.out.println("array type description = " + t.getDescription());
343 * }</pre>
344 * would produce the following output:
345 * <pre>{@code
346 * array class name = [I
347 * element class name = java.lang.Integer
348 * array type name = [I
349 * array type description = 1-dimension array of int
350 * }</pre>
351 *
352 * @param elementType the {@code SimpleType} of the element values
353 * contained in the arrays described by this
466 final String primitiveType =
467 getPrimitiveTypeName(elementClassName);
468
469 // Ideally we should throw an IllegalArgumentException here,
470 // but for compatibility reasons we throw an OpenDataException.
471 // (used to be thrown by OpenType() constructor).
472 //
473 if (primitiveType == null)
474 throw new OpenDataException("Element is not a primitive type: "+
475 elementClassName);
476 result.append(primitiveType);
477 } else {
478 result.append(elementClassName);
479 }
480 return result.toString();
481 }
482
483 /* *** ArrayType specific information methods *** */
484
485 /**
486 * Returns the dimension of arrays described by this <tt>ArrayType</tt> instance.
487 *
488 * @return the dimension.
489 */
490 public int getDimension() {
491
492 return dimension;
493 }
494
495 /**
496 * Returns the <i>open type</i> of element values contained in the arrays described by this <tt>ArrayType</tt> instance.
497 *
498 * @return the element type.
499 */
500 public OpenType<?> getElementOpenType() {
501
502 return elementType;
503 }
504
505 /**
506 * Returns <code>true</code> if the open data values this open
507 * type describes are primitive arrays, <code>false</code> otherwise.
508 *
509 * @return true if this is a primitive array type.
510 *
511 * @since 1.6
512 */
513 public boolean isPrimitiveArray() {
514
515 return primitiveArray;
516 }
517
518 /**
519 * Tests whether <var>obj</var> is a value for this <code>ArrayType</code>
520 * instance.
521 * <p>
522 * This method returns <code>true</code> if and only if <var>obj</var>
523 * is not null, <var>obj</var> is an array and any one of the following
524 * is <tt>true</tt>:
525 *
526 * <ul>
527 * <li>if this <code>ArrayType</code> instance describes an array of
528 * <tt>SimpleType</tt> elements or their corresponding primitive types,
529 * <var>obj</var>'s class name is the same as the className field defined
530 * for this <code>ArrayType</code> instance (i.e. the class name returned
531 * by the {@link OpenType#getClassName() getClassName} method, which
532 * includes the dimension information),<br> </li>
533 * <li>if this <code>ArrayType</code> instance describes an array of
534 * classes implementing the {@code TabularData} interface or the
535 * {@code CompositeData} interface, <var>obj</var> is assignable to
536 * such a declared array, and each element contained in {<var>obj</var>
537 * is either null or a valid value for the element's open type specified
538 * by this <code>ArrayType</code> instance.</li>
539 * </ul>
540 *
541 * @param obj the object to be tested.
542 *
543 * @return <code>true</code> if <var>obj</var> is a value for this
544 * <code>ArrayType</code> instance.
545 */
546 public boolean isValue(Object obj) {
547
548 // if obj is null, return false
549 //
550 if (obj == null) {
551 return false;
552 }
553
554 Class<?> objClass = obj.getClass();
555 String objClassName = objClass.getName();
556
557 // if obj is not an array, return false
558 //
559 if ( ! objClass.isArray() ) {
560 return false;
561 }
562
563 // Test if obj's class name is the same as for the array values that this instance describes
564 // (this is fine if elements are of simple types, which are final classes)
632 }
633 }
634 return true;
635 }
636 }
637
638 @Override
639 boolean isAssignableFrom(OpenType<?> ot) {
640 if (!(ot instanceof ArrayType<?>))
641 return false;
642 ArrayType<?> at = (ArrayType<?>) ot;
643 return (at.getDimension() == getDimension() &&
644 at.isPrimitiveArray() == isPrimitiveArray() &&
645 at.getElementOpenType().isAssignableFrom(getElementOpenType()));
646 }
647
648
649 /* *** Methods overriden from class Object *** */
650
651 /**
652 * Compares the specified <code>obj</code> parameter with this
653 * <code>ArrayType</code> instance for equality.
654 * <p>
655 * Two <code>ArrayType</code> instances are equal if and only if they
656 * describe array instances which have the same dimension, elements'
657 * open type and primitive array flag.
658 *
659 * @param obj the object to be compared for equality with this
660 * <code>ArrayType</code> instance; if <var>obj</var>
661 * is <code>null</code> or is not an instance of the
662 * class <code>ArrayType</code> this method returns
663 * <code>false</code>.
664 *
665 * @return <code>true</code> if the specified object is equal to
666 * this <code>ArrayType</code> instance.
667 */
668 public boolean equals(Object obj) {
669
670 // if obj is null, return false
671 //
672 if (obj == null) {
673 return false;
674 }
675
676 // if obj is not an ArrayType, return false
677 //
678 if (!(obj instanceof ArrayType<?>))
679 return false;
680 ArrayType<?> other = (ArrayType<?>) obj;
681
682 // if other's dimension is different than this instance's, return false
683 //
684 if (this.dimension != other.dimension) {
685 return false;
686 }
687
688 // Test if other's elementType field is the same as for this instance
689 //
690 if (!this.elementType.equals(other.elementType)) {
691 return false;
692 }
693
694 // Test if other's primitiveArray flag is the same as for this instance
695 //
696 return this.primitiveArray == other.primitiveArray;
697 }
698
699 /**
700 * Returns the hash code value for this <code>ArrayType</code> instance.
701 * <p>
702 * The hash code of an <code>ArrayType</code> instance is the sum of the
703 * hash codes of all the elements of information used in <code>equals</code>
704 * comparisons (i.e. dimension, elements' open type and primitive array flag).
705 * The hashcode for a primitive value is the hashcode of the corresponding boxed
706 * object (e.g. the hashcode for <tt>true</tt> is <tt>Boolean.TRUE.hashCode()</tt>).
707 * This ensures that <code> t1.equals(t2) </code> implies that
708 * <code> t1.hashCode()==t2.hashCode() </code> for any two
709 * <code>ArrayType</code> instances <code>t1</code> and <code>t2</code>,
710 * as required by the general contract of the method
711 * {@link Object#hashCode() Object.hashCode()}.
712 * <p>
713 * As <code>ArrayType</code> instances are immutable, the hash
714 * code for this instance is calculated once, on the first call
715 * to <code>hashCode</code>, and then the same value is returned
716 * for subsequent calls.
717 *
718 * @return the hash code value for this <code>ArrayType</code> instance
719 */
720 public int hashCode() {
721
722 // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
723 //
724 if (myHashCode == null) {
725 int value = 0;
726 value += dimension;
727 value += elementType.hashCode();
728 value += Boolean.valueOf(primitiveArray).hashCode();
729 myHashCode = Integer.valueOf(value);
730 }
731
732 // return always the same hash code for this instance (immutable)
733 //
734 return myHashCode.intValue();
735 }
736
737 /**
738 * Returns a string representation of this <code>ArrayType</code> instance.
739 * <p>
740 * The string representation consists of the name of this class (i.e.
741 * <code>javax.management.openmbean.ArrayType</code>), the type name,
742 * the dimension, the elements' open type and the primitive array flag
743 * defined for this instance.
744 * <p>
745 * As <code>ArrayType</code> instances are immutable, the
746 * string representation for this instance is calculated
747 * once, on the first call to <code>toString</code>, and
748 * then the same value is returned for subsequent calls.
749 *
750 * @return a string representation of this <code>ArrayType</code> instance
751 */
752 public String toString() {
753
754 // Calculate the string representation if it has not yet been done (ie 1st call to toString())
755 //
756 if (myToString == null) {
757 myToString = getClass().getName() +
758 "(name=" + getTypeName() +
759 ",dimension=" + dimension +
760 ",elementType=" + elementType +
761 ",primitiveArray=" + primitiveArray + ")";
762 }
763
764 // return always the same string representation for this instance (immutable)
765 //
766 return myToString;
767 }
768
769 /**
770 * Create an {@code ArrayType} instance in a type-safe manner.
778 * As an example, the following piece of code:
779 * <pre>{@code
780 * ArrayType<String[]> t1 = ArrayType.getArrayType(SimpleType.STRING);
781 * ArrayType<String[][]> t2 = ArrayType.getArrayType(t1);
782 * ArrayType<String[][][]> t3 = ArrayType.getArrayType(t2);
783 * System.out.println("array class name = " + t3.getClassName());
784 * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
785 * System.out.println("array type name = " + t3.getTypeName());
786 * System.out.println("array type description = " + t3.getDescription());
787 * }</pre>
788 * would produce the following output:
789 * <pre>{@code
790 * array class name = [[[Ljava.lang.String;
791 * element class name = java.lang.String
792 * array type name = [[[Ljava.lang.String;
793 * array type description = 3-dimension array of java.lang.String
794 * }</pre>
795 *
796 * @param <E> the Java type that described instances must have
797 * @param elementType the <i>open type</i> of element values contained
798 * in the arrays described by this <tt>ArrayType</tt>
799 * instance; must be an instance of either
800 * <tt>SimpleType</tt>, <tt>CompositeType</tt>,
801 * <tt>TabularType</tt> or another <tt>ArrayType</tt>
802 * with a <tt>SimpleType</tt>, <tt>CompositeType</tt>
803 * or <tt>TabularType</tt> as its <tt>elementType</tt>.
804 * @return an {@code ArrayType} instance
805 * @throws OpenDataException if <var>elementType's className</var> is not
806 * one of the allowed Java class names for open
807 * data.
808 *
809 * @since 1.6
810 */
811 public static <E> ArrayType<E[]> getArrayType(OpenType<E> elementType)
812 throws OpenDataException {
813 return new ArrayType<E[]>(1, elementType);
814 }
815
816 /**
817 * Create an {@code ArrayType} instance in a type-safe manner.
818 * <p>
819 * Calling this method twice with the same parameters may return the
820 * same object or two equal but not identical objects.
821 * <p>
822 * As an example, the following piece of code:
823 * <pre>{@code
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.management.openmbean;
27
28 import java.io.ObjectStreamException;
29 import java.lang.reflect.Array;
30
31 /**
32 * The {@code ArrayType} class is the <i>open type</i> class whose instances describe
33 * all <i>open data</i> values which are n-dimensional arrays of <i>open data</i> values.
34 * <p>
35 * Examples of valid {@code ArrayType} instances are:
36 * <pre>{@code
37 * // 2-dimension array of java.lang.String
38 * ArrayType<String[][]> a1 = new ArrayType<String[][]>(2, SimpleType.STRING);
39 *
40 * // 1-dimension array of int
41 * ArrayType<int[]> a2 = new ArrayType<int[]>(SimpleType.INTEGER, true);
42 *
43 * // 1-dimension array of java.lang.Integer
44 * ArrayType<Integer[]> a3 = new ArrayType<Integer[]>(SimpleType.INTEGER, false);
45 *
46 * // 4-dimension array of int
47 * ArrayType<int[][][][]> a4 = new ArrayType<int[][][][]>(3, a2);
48 *
49 * // 4-dimension array of java.lang.Integer
50 * ArrayType<Integer[][][][]> a5 = new ArrayType<Integer[][][][]>(3, a3);
51 *
52 * // 1-dimension array of java.lang.String
205 * e.g. SimpleType.BOOLEAN for "boolean", SimpleType.CHARACTER for
206 * "char", etc...
207 * @param primitiveTypeName the primitive type of the array element ("boolean",
208 * "char", etc...)
209 * @return the OpenType corresponding to the given primitive type name
210 * (SimpleType.BOOLEAN, SimpleType.CHARACTER, etc...)
211 * return null if the given elementClassName is not a primitive
212 * type name.
213 **/
214 static SimpleType<?> getPrimitiveOpenType(String primitiveTypeName) {
215 for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
216 if (primitiveTypeName.equals(typeDescr[PRIMITIVE_TYPE_NAME_INDEX]))
217 return (SimpleType<?>)typeDescr[PRIMITIVE_OPEN_TYPE_INDEX];
218 }
219 return null;
220 }
221
222 /* *** Constructor *** */
223
224 /**
225 * Constructs an {@code ArrayType} instance describing <i>open data</i> values which are
226 * arrays with dimension <var>dimension</var> of elements
227 * whose <i>open type</i> is <var>elementType</var>.
228 * <p>
229 * When invoked on an {@code ArrayType} instance,
230 * the {@link OpenType#getClassName() getClassName} method
231 * returns the class name of the array instances it describes
232 * (following the rules defined by the
233 * {@link Class#getName() getName} method of {@code java.lang.Class}),
234 * not the class name of the array elements
235 * (which is returned by a call to {@code getElementOpenType().getClassName()}).
236 * <p>
237 * The internal field corresponding to the type name of this
238 * {@code ArrayType} instance is also set to
239 * the class name of the array instances it describes.
240 * In other words, the methods {@code getClassName} and
241 * {@code getTypeName} return the same string value.
242 * The internal field corresponding to the description of this
243 * {@code ArrayType} instance is set to a string value
244 * which follows the following template:
245 * <ul>
246 * <li>if non-primitive array: <code><i><dimension></i>-dimension array
247 * of <i><element_class_name></i></code></li>
248 * <li>if primitive array: <code><i><dimension></i>-dimension array
249 * of <i><primitive_type_of_the_element_class_name></i></code></li>
250 * </ul>
251 * <p>
252 * As an example, the following piece of code:
253 * <pre>{@code
254 * ArrayType<String[][][]> t = new ArrayType<String[][][]>(3, SimpleType.STRING);
255 * System.out.println("array class name = " + t.getClassName());
256 * System.out.println("element class name = " + t.getElementOpenType().getClassName());
257 * System.out.println("array type name = " + t.getTypeName());
258 * System.out.println("array type description = " + t.getDescription());
259 * }</pre>
260 * would produce the following output:
261 * <pre>{@code
262 * array class name = [[[Ljava.lang.String;
263 * element class name = java.lang.String
264 * array type name = [[[Ljava.lang.String;
265 * array type description = 3-dimension array of java.lang.String
266 * }</pre>
267 * And the following piece of code which is equivalent to the one listed
268 * above would also produce the same output:
269 * <pre>{@code
270 * ArrayType<String[]> t1 = new ArrayType<String[]>(1, SimpleType.STRING);
271 * ArrayType<String[][]> t2 = new ArrayType<String[][]>(1, t1);
272 * ArrayType<String[][][]> t3 = new ArrayType<String[][][]>(1, t2);
273 * System.out.println("array class name = " + t3.getClassName());
274 * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
275 * System.out.println("array type name = " + t3.getTypeName());
276 * System.out.println("array type description = " + t3.getDescription());
277 * }</pre>
278 *
279 * @param dimension the dimension of arrays described by this {@code ArrayType} instance;
280 * must be greater than or equal to 1.
281 *
282 * @param elementType the <i>open type</i> of element values contained
283 * in the arrays described by this {@code ArrayType}
284 * instance; must be an instance of either
285 * {@code SimpleType}, {@code CompositeType},
286 * {@code TabularType} or another {@code ArrayType}
287 * with a {@code SimpleType}, {@code CompositeType}
288 * or {@code TabularType} as its {@code elementType}.
289 *
290 * @throws IllegalArgumentException if {@code dimension} is not a positive
291 * integer.
292 * @throws OpenDataException if <var>elementType's className</var> is not
293 * one of the allowed Java class names for open
294 * data.
295 */
296 public ArrayType(int dimension,
297 OpenType<?> elementType) throws OpenDataException {
298 // Check and construct state defined by parent.
299 // We can't use the package-private OpenType constructor because
300 // we don't know if the elementType parameter is sane.
301 super(buildArrayClassName(dimension, elementType),
302 buildArrayClassName(dimension, elementType),
303 buildArrayDescription(dimension, elementType));
304
305 // Check and construct state specific to ArrayType
306 //
307 if (elementType.isArray()) {
308 ArrayType<?> at = (ArrayType<?>) elementType;
310 this.elementType = at.getElementOpenType();
311 this.primitiveArray = at.isPrimitiveArray();
312 } else {
313 this.dimension = dimension;
314 this.elementType = elementType;
315 this.primitiveArray = false;
316 }
317 }
318
319 /**
320 * Constructs a unidimensional {@code ArrayType} instance for the
321 * supplied {@code SimpleType}.
322 * <p>
323 * This constructor supports the creation of arrays of primitive
324 * types when {@code primitiveArray} is {@code true}.
325 * <p>
326 * For primitive arrays the {@link #getElementOpenType()} method
327 * returns the {@link SimpleType} corresponding to the wrapper
328 * type of the primitive type of the array.
329 * <p>
330 * When invoked on an {@code ArrayType} instance,
331 * the {@link OpenType#getClassName() getClassName} method
332 * returns the class name of the array instances it describes
333 * (following the rules defined by the
334 * {@link Class#getName() getName} method of {@code java.lang.Class}),
335 * not the class name of the array elements
336 * (which is returned by a call to {@code getElementOpenType().getClassName()}).
337 * <p>
338 * The internal field corresponding to the type name of this
339 * {@code ArrayType} instance is also set to
340 * the class name of the array instances it describes.
341 * In other words, the methods {@code getClassName} and
342 * {@code getTypeName} return the same string value.
343 * The internal field corresponding to the description
344 * of this {@code ArrayType} instance is set to a string value
345 * which follows the following template:
346 * <ul>
347 * <li>if non-primitive array: <code>1-dimension array
348 * of <i><element_class_name></i></code></li>
349 * <li>if primitive array: <code>1-dimension array
350 * of <i><primitive_type_of_the_element_class_name></i></code></li>
351 * </ul>
352 * <p>
353 * As an example, the following piece of code:
354 * <pre>{@code
355 * ArrayType<int[]> t = new ArrayType<int[]>(SimpleType.INTEGER, true);
356 * System.out.println("array class name = " + t.getClassName());
357 * System.out.println("element class name = " + t.getElementOpenType().getClassName());
358 * System.out.println("array type name = " + t.getTypeName());
359 * System.out.println("array type description = " + t.getDescription());
360 * }</pre>
361 * would produce the following output:
362 * <pre>{@code
363 * array class name = [I
364 * element class name = java.lang.Integer
365 * array type name = [I
366 * array type description = 1-dimension array of int
367 * }</pre>
368 *
369 * @param elementType the {@code SimpleType} of the element values
370 * contained in the arrays described by this
483 final String primitiveType =
484 getPrimitiveTypeName(elementClassName);
485
486 // Ideally we should throw an IllegalArgumentException here,
487 // but for compatibility reasons we throw an OpenDataException.
488 // (used to be thrown by OpenType() constructor).
489 //
490 if (primitiveType == null)
491 throw new OpenDataException("Element is not a primitive type: "+
492 elementClassName);
493 result.append(primitiveType);
494 } else {
495 result.append(elementClassName);
496 }
497 return result.toString();
498 }
499
500 /* *** ArrayType specific information methods *** */
501
502 /**
503 * Returns the dimension of arrays described by this {@code ArrayType} instance.
504 *
505 * @return the dimension.
506 */
507 public int getDimension() {
508
509 return dimension;
510 }
511
512 /**
513 * Returns the <i>open type</i> of element values contained
514 * in the arrays described by this {@code ArrayType} instance.
515 *
516 * @return the element type.
517 */
518 public OpenType<?> getElementOpenType() {
519
520 return elementType;
521 }
522
523 /**
524 * Returns {@code true} if the open data values this open
525 * type describes are primitive arrays, {@code false} otherwise.
526 *
527 * @return true if this is a primitive array type.
528 *
529 * @since 1.6
530 */
531 public boolean isPrimitiveArray() {
532
533 return primitiveArray;
534 }
535
536 /**
537 * Tests whether <var>obj</var> is a value for this {@code ArrayType}
538 * instance.
539 * <p>
540 * This method returns {@code true} if and only if <var>obj</var>
541 * is not null, <var>obj</var> is an array and any one of the following
542 * is {@code true}:
543 *
544 * <ul>
545 * <li>if this {@code ArrayType} instance describes an array of
546 * {@code SimpleType} elements or their corresponding primitive types,
547 * <var>obj</var>'s class name is the same as the className field defined
548 * for this {@code ArrayType} instance (i.e. the class name returned
549 * by the {@link OpenType#getClassName() getClassName} method, which
550 * includes the dimension information),<br> </li>
551 * <li>if this {@code ArrayType} instance describes an array of
552 * classes implementing the {@code TabularData} interface or the
553 * {@code CompositeData} interface, <var>obj</var> is assignable to
554 * such a declared array, and each element contained in {<var>obj</var>
555 * is either null or a valid value for the element's open type specified
556 * by this {@code ArrayType} instance.</li>
557 * </ul>
558 *
559 * @param obj the object to be tested.
560 *
561 * @return {@code true} if <var>obj</var> is a value for this
562 * {@code ArrayType} instance.
563 */
564 public boolean isValue(Object obj) {
565
566 // if obj is null, return false
567 //
568 if (obj == null) {
569 return false;
570 }
571
572 Class<?> objClass = obj.getClass();
573 String objClassName = objClass.getName();
574
575 // if obj is not an array, return false
576 //
577 if ( ! objClass.isArray() ) {
578 return false;
579 }
580
581 // Test if obj's class name is the same as for the array values that this instance describes
582 // (this is fine if elements are of simple types, which are final classes)
650 }
651 }
652 return true;
653 }
654 }
655
656 @Override
657 boolean isAssignableFrom(OpenType<?> ot) {
658 if (!(ot instanceof ArrayType<?>))
659 return false;
660 ArrayType<?> at = (ArrayType<?>) ot;
661 return (at.getDimension() == getDimension() &&
662 at.isPrimitiveArray() == isPrimitiveArray() &&
663 at.getElementOpenType().isAssignableFrom(getElementOpenType()));
664 }
665
666
667 /* *** Methods overriden from class Object *** */
668
669 /**
670 * Compares the specified {@code obj} parameter with this
671 * {@code ArrayType} instance for equality.
672 * <p>
673 * Two {@code ArrayType} instances are equal if and only if they
674 * describe array instances which have the same dimension, elements'
675 * open type and primitive array flag.
676 *
677 * @param obj the object to be compared for equality with this
678 * {@code ArrayType} instance; if <var>obj</var>
679 * is {@code null} or is not an instance of the
680 * class {@code ArrayType} this method returns
681 * {@code false}.
682 *
683 * @return {@code true} if the specified object is equal to
684 * this {@code ArrayType} instance.
685 */
686 public boolean equals(Object obj) {
687
688 // if obj is null, return false
689 //
690 if (obj == null) {
691 return false;
692 }
693
694 // if obj is not an ArrayType, return false
695 //
696 if (!(obj instanceof ArrayType<?>))
697 return false;
698 ArrayType<?> other = (ArrayType<?>) obj;
699
700 // if other's dimension is different than this instance's, return false
701 //
702 if (this.dimension != other.dimension) {
703 return false;
704 }
705
706 // Test if other's elementType field is the same as for this instance
707 //
708 if (!this.elementType.equals(other.elementType)) {
709 return false;
710 }
711
712 // Test if other's primitiveArray flag is the same as for this instance
713 //
714 return this.primitiveArray == other.primitiveArray;
715 }
716
717 /**
718 * Returns the hash code value for this {@code ArrayType} instance.
719 * <p>
720 * The hash code of an {@code ArrayType} instance is the sum of the
721 * hash codes of all the elements of information used in {@code equals}
722 * comparisons (i.e. dimension, elements' open type and primitive array flag).
723 * The hashcode for a primitive value is the hashcode of the corresponding boxed
724 * object (e.g. the hashcode for {@code true} is {@code Boolean.TRUE.hashCode()}).
725 * This ensures that {@code t1.equals(t2)} implies that
726 * {@code t1.hashCode()==t2.hashCode()} for any two
727 * {@code ArrayType} instances {@code t1} and {@code t2},
728 * as required by the general contract of the method
729 * {@link Object#hashCode() Object.hashCode()}.
730 * <p>
731 * As {@code ArrayType} instances are immutable, the hash
732 * code for this instance is calculated once, on the first call
733 * to {@code hashCode}, and then the same value is returned
734 * for subsequent calls.
735 *
736 * @return the hash code value for this {@code ArrayType} instance
737 */
738 public int hashCode() {
739
740 // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
741 //
742 if (myHashCode == null) {
743 int value = 0;
744 value += dimension;
745 value += elementType.hashCode();
746 value += Boolean.valueOf(primitiveArray).hashCode();
747 myHashCode = Integer.valueOf(value);
748 }
749
750 // return always the same hash code for this instance (immutable)
751 //
752 return myHashCode.intValue();
753 }
754
755 /**
756 * Returns a string representation of this {@code ArrayType} instance.
757 * <p>
758 * The string representation consists of the name of this class (i.e.
759 * {@code javax.management.openmbean.ArrayType}), the type name,
760 * the dimension, the elements' open type and the primitive array flag
761 * defined for this instance.
762 * <p>
763 * As {@code ArrayType} instances are immutable, the
764 * string representation for this instance is calculated
765 * once, on the first call to {@code toString}, and
766 * then the same value is returned for subsequent calls.
767 *
768 * @return a string representation of this {@code ArrayType} instance
769 */
770 public String toString() {
771
772 // Calculate the string representation if it has not yet been done (ie 1st call to toString())
773 //
774 if (myToString == null) {
775 myToString = getClass().getName() +
776 "(name=" + getTypeName() +
777 ",dimension=" + dimension +
778 ",elementType=" + elementType +
779 ",primitiveArray=" + primitiveArray + ")";
780 }
781
782 // return always the same string representation for this instance (immutable)
783 //
784 return myToString;
785 }
786
787 /**
788 * Create an {@code ArrayType} instance in a type-safe manner.
796 * As an example, the following piece of code:
797 * <pre>{@code
798 * ArrayType<String[]> t1 = ArrayType.getArrayType(SimpleType.STRING);
799 * ArrayType<String[][]> t2 = ArrayType.getArrayType(t1);
800 * ArrayType<String[][][]> t3 = ArrayType.getArrayType(t2);
801 * System.out.println("array class name = " + t3.getClassName());
802 * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
803 * System.out.println("array type name = " + t3.getTypeName());
804 * System.out.println("array type description = " + t3.getDescription());
805 * }</pre>
806 * would produce the following output:
807 * <pre>{@code
808 * array class name = [[[Ljava.lang.String;
809 * element class name = java.lang.String
810 * array type name = [[[Ljava.lang.String;
811 * array type description = 3-dimension array of java.lang.String
812 * }</pre>
813 *
814 * @param <E> the Java type that described instances must have
815 * @param elementType the <i>open type</i> of element values contained
816 * in the arrays described by this {@code ArrayType}
817 * instance; must be an instance of either
818 * {@code SimpleType}, {@code CompositeType},
819 * {@code TabularType} or another {@code ArrayType}
820 * with a {@code SimpleType}, {@code CompositeType}
821 * or {@code TabularType} as its {@code elementType}.
822 * @return an {@code ArrayType} instance
823 * @throws OpenDataException if <var>elementType's className</var> is not
824 * one of the allowed Java class names for open
825 * data.
826 *
827 * @since 1.6
828 */
829 public static <E> ArrayType<E[]> getArrayType(OpenType<E> elementType)
830 throws OpenDataException {
831 return new ArrayType<E[]>(1, elementType);
832 }
833
834 /**
835 * Create an {@code ArrayType} instance in a type-safe manner.
836 * <p>
837 * Calling this method twice with the same parameters may return the
838 * same object or two equal but not identical objects.
839 * <p>
840 * As an example, the following piece of code:
841 * <pre>{@code
|