001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.util;
018
019import java.lang.reflect.Array;
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.Map;
023
024/**
025 * Miscellaneous object utility methods.
026 *
027 * <p>Mainly for internal use within the framework.
028 *
029 * <p>Thanks to Alex Ruiz for contributing several enhancements to this class!
030 *
031 * @author Juergen Hoeller
032 * @author Keith Donald
033 * @author Rod Johnson
034 * @author Rob Harrop
035 * @author Chris Beams
036 * @author Sam Brannen
037 * @since 19.03.2004
038 * @see ClassUtils
039 * @see CollectionUtils
040 * @see StringUtils
041 */
042public abstract class ObjectUtils {
043
044        private static final int INITIAL_HASH = 7;
045        private static final int MULTIPLIER = 31;
046
047        private static final String EMPTY_STRING = "";
048        private static final String NULL_STRING = "null";
049        private static final String ARRAY_START = "{";
050        private static final String ARRAY_END = "}";
051        private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
052        private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
053
054
055        /**
056         * Return whether the given throwable is a checked exception:
057         * that is, neither a RuntimeException nor an Error.
058         * @param ex the throwable to check
059         * @return whether the throwable is a checked exception
060         * @see java.lang.Exception
061         * @see java.lang.RuntimeException
062         * @see java.lang.Error
063         */
064        public static boolean isCheckedException(Throwable ex) {
065                return !(ex instanceof RuntimeException || ex instanceof Error);
066        }
067
068        /**
069         * Check whether the given exception is compatible with the specified
070         * exception types, as declared in a throws clause.
071         * @param ex the exception to check
072         * @param declaredExceptions the exception types declared in the throws clause
073         * @return whether the given exception is compatible
074         */
075        public static boolean isCompatibleWithThrowsClause(Throwable ex, Class<?>... declaredExceptions) {
076                if (!isCheckedException(ex)) {
077                        return true;
078                }
079                if (declaredExceptions != null) {
080                        for (Class<?> declaredException : declaredExceptions) {
081                                if (declaredException.isInstance(ex)) {
082                                        return true;
083                                }
084                        }
085                }
086                return false;
087        }
088
089        /**
090         * Determine whether the given object is an array:
091         * either an Object array or a primitive array.
092         * @param obj the object to check
093         */
094        public static boolean isArray(Object obj) {
095                return (obj != null && obj.getClass().isArray());
096        }
097
098        /**
099         * Determine whether the given array is empty:
100         * i.e. {@code null} or of zero length.
101         * @param array the array to check
102         * @see #isEmpty(Object)
103         */
104        public static boolean isEmpty(Object[] array) {
105                return (array == null || array.length == 0);
106        }
107
108        /**
109         * Determine whether the given object is empty.
110         * <p>This method supports the following object types.
111         * <ul>
112         * <li>{@code Array}: considered empty if its length is zero</li>
113         * <li>{@link CharSequence}: considered empty if its length is zero</li>
114         * <li>{@link Collection}: delegates to {@link Collection#isEmpty()}</li>
115         * <li>{@link Map}: delegates to {@link Map#isEmpty()}</li>
116         * </ul>
117         * <p>If the given object is non-null and not one of the aforementioned
118         * supported types, this method returns {@code false}.
119         * @param obj the object to check
120         * @return {@code true} if the object is {@code null} or <em>empty</em>
121         * @since 4.2
122         * @see ObjectUtils#isEmpty(Object[])
123         * @see StringUtils#hasLength(CharSequence)
124         * @see StringUtils#isEmpty(Object)
125         * @see CollectionUtils#isEmpty(java.util.Collection)
126         * @see CollectionUtils#isEmpty(java.util.Map)
127         */
128        @SuppressWarnings("rawtypes")
129        public static boolean isEmpty(Object obj) {
130                if (obj == null) {
131                        return true;
132                }
133
134                if (obj instanceof CharSequence) {
135                        return ((CharSequence) obj).length() == 0;
136                }
137                if (obj.getClass().isArray()) {
138                        return Array.getLength(obj) == 0;
139                }
140                if (obj instanceof Collection) {
141                        return ((Collection) obj).isEmpty();
142                }
143                if (obj instanceof Map) {
144                        return ((Map) obj).isEmpty();
145                }
146
147                // else
148                return false;
149        }
150
151        /**
152         * Check whether the given array contains the given element.
153         * @param array the array to check (may be {@code null},
154         * in which case the return value will always be {@code false})
155         * @param element the element to check for
156         * @return whether the element has been found in the given array
157         */
158        public static boolean containsElement(Object[] array, Object element) {
159                if (array == null) {
160                        return false;
161                }
162                for (Object arrayEle : array) {
163                        if (nullSafeEquals(arrayEle, element)) {
164                                return true;
165                        }
166                }
167                return false;
168        }
169
170        /**
171         * Check whether the given array of enum constants contains a constant with the given name,
172         * ignoring case when determining a match.
173         * @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
174         * @param constant the constant name to find (must not be null or empty string)
175         * @return whether the constant has been found in the given array
176         */
177        public static boolean containsConstant(Enum<?>[] enumValues, String constant) {
178                return containsConstant(enumValues, constant, false);
179        }
180
181        /**
182         * Check whether the given array of enum constants contains a constant with the given name.
183         * @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
184         * @param constant the constant name to find (must not be null or empty string)
185         * @param caseSensitive whether case is significant in determining a match
186         * @return whether the constant has been found in the given array
187         */
188        public static boolean containsConstant(Enum<?>[] enumValues, String constant, boolean caseSensitive) {
189                for (Enum<?> candidate : enumValues) {
190                        if (caseSensitive ? candidate.toString().equals(constant) :
191                                        candidate.toString().equalsIgnoreCase(constant)) {
192                                return true;
193                        }
194                }
195                return false;
196        }
197
198        /**
199         * Case insensitive alternative to {@link Enum#valueOf(Class, String)}.
200         * @param <E> the concrete Enum type
201         * @param enumValues the array of all Enum constants in question, usually per {@code Enum.values()}
202         * @param constant the constant to get the enum value of
203         * @throws IllegalArgumentException if the given constant is not found in the given array
204         * of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to avoid this exception.
205         */
206        public static <E extends Enum<?>> E caseInsensitiveValueOf(E[] enumValues, String constant) {
207                for (E candidate : enumValues) {
208                        if (candidate.toString().equalsIgnoreCase(constant)) {
209                                return candidate;
210                        }
211                }
212                throw new IllegalArgumentException("Constant [" + constant + "] does not exist in enum type " +
213                                enumValues.getClass().getComponentType().getName());
214        }
215
216        /**
217         * Append the given object to the given array, returning a new array
218         * consisting of the input array contents plus the given object.
219         * @param array the array to append to (can be {@code null})
220         * @param obj the object to append
221         * @return the new array (of the same component type; never {@code null})
222         */
223        public static <A, O extends A> A[] addObjectToArray(A[] array, O obj) {
224                Class<?> compType = Object.class;
225                if (array != null) {
226                        compType = array.getClass().getComponentType();
227                }
228                else if (obj != null) {
229                        compType = obj.getClass();
230                }
231                int newArrLength = (array != null ? array.length + 1 : 1);
232                @SuppressWarnings("unchecked")
233                A[] newArr = (A[]) Array.newInstance(compType, newArrLength);
234                if (array != null) {
235                        System.arraycopy(array, 0, newArr, 0, array.length);
236                }
237                newArr[newArr.length - 1] = obj;
238                return newArr;
239        }
240
241        /**
242         * Convert the given array (which may be a primitive array) to an
243         * object array (if necessary of primitive wrapper objects).
244         * <p>A {@code null} source value will be converted to an
245         * empty Object array.
246         * @param source the (potentially primitive) array
247         * @return the corresponding object array (never {@code null})
248         * @throws IllegalArgumentException if the parameter is not an array
249         */
250        public static Object[] toObjectArray(Object source) {
251                if (source instanceof Object[]) {
252                        return (Object[]) source;
253                }
254                if (source == null) {
255                        return new Object[0];
256                }
257                if (!source.getClass().isArray()) {
258                        throw new IllegalArgumentException("Source is not an array: " + source);
259                }
260                int length = Array.getLength(source);
261                if (length == 0) {
262                        return new Object[0];
263                }
264                Class<?> wrapperType = Array.get(source, 0).getClass();
265                Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);
266                for (int i = 0; i < length; i++) {
267                        newArray[i] = Array.get(source, i);
268                }
269                return newArray;
270        }
271
272
273        //---------------------------------------------------------------------
274        // Convenience methods for content-based equality/hash-code handling
275        //---------------------------------------------------------------------
276
277        /**
278         * Determine if the given objects are equal, returning {@code true} if
279         * both are {@code null} or {@code false} if only one is {@code null}.
280         * <p>Compares arrays with {@code Arrays.equals}, performing an equality
281         * check based on the array elements rather than the array reference.
282         * @param o1 first Object to compare
283         * @param o2 second Object to compare
284         * @return whether the given objects are equal
285         * @see Object#equals(Object)
286         * @see java.util.Arrays#equals
287         */
288        public static boolean nullSafeEquals(Object o1, Object o2) {
289                if (o1 == o2) {
290                        return true;
291                }
292                if (o1 == null || o2 == null) {
293                        return false;
294                }
295                if (o1.equals(o2)) {
296                        return true;
297                }
298                if (o1.getClass().isArray() && o2.getClass().isArray()) {
299                        return arrayEquals(o1, o2);
300                }
301                return false;
302        }
303
304        /**
305         * Compare the given arrays with {@code Arrays.equals}, performing an equality
306         * check based on the array elements rather than the array reference.
307         * @param o1 first array to compare
308         * @param o2 second array to compare
309         * @return whether the given objects are equal
310         * @see #nullSafeEquals(Object, Object)
311         * @see java.util.Arrays#equals
312         */
313        private static boolean arrayEquals(Object o1, Object o2) {
314                if (o1 instanceof Object[] && o2 instanceof Object[]) {
315                        return Arrays.equals((Object[]) o1, (Object[]) o2);
316                }
317                if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
318                        return Arrays.equals((boolean[]) o1, (boolean[]) o2);
319                }
320                if (o1 instanceof byte[] && o2 instanceof byte[]) {
321                        return Arrays.equals((byte[]) o1, (byte[]) o2);
322                }
323                if (o1 instanceof char[] && o2 instanceof char[]) {
324                        return Arrays.equals((char[]) o1, (char[]) o2);
325                }
326                if (o1 instanceof double[] && o2 instanceof double[]) {
327                        return Arrays.equals((double[]) o1, (double[]) o2);
328                }
329                if (o1 instanceof float[] && o2 instanceof float[]) {
330                        return Arrays.equals((float[]) o1, (float[]) o2);
331                }
332                if (o1 instanceof int[] && o2 instanceof int[]) {
333                        return Arrays.equals((int[]) o1, (int[]) o2);
334                }
335                if (o1 instanceof long[] && o2 instanceof long[]) {
336                        return Arrays.equals((long[]) o1, (long[]) o2);
337                }
338                if (o1 instanceof short[] && o2 instanceof short[]) {
339                        return Arrays.equals((short[]) o1, (short[]) o2);
340                }
341                return false;
342        }
343
344        /**
345         * Return as hash code for the given object; typically the value of
346         * {@code Object#hashCode()}}. If the object is an array,
347         * this method will delegate to any of the {@code nullSafeHashCode}
348         * methods for arrays in this class. If the object is {@code null},
349         * this method returns 0.
350         * @see Object#hashCode()
351         * @see #nullSafeHashCode(Object[])
352         * @see #nullSafeHashCode(boolean[])
353         * @see #nullSafeHashCode(byte[])
354         * @see #nullSafeHashCode(char[])
355         * @see #nullSafeHashCode(double[])
356         * @see #nullSafeHashCode(float[])
357         * @see #nullSafeHashCode(int[])
358         * @see #nullSafeHashCode(long[])
359         * @see #nullSafeHashCode(short[])
360         */
361        public static int nullSafeHashCode(Object obj) {
362                if (obj == null) {
363                        return 0;
364                }
365                if (obj.getClass().isArray()) {
366                        if (obj instanceof Object[]) {
367                                return nullSafeHashCode((Object[]) obj);
368                        }
369                        if (obj instanceof boolean[]) {
370                                return nullSafeHashCode((boolean[]) obj);
371                        }
372                        if (obj instanceof byte[]) {
373                                return nullSafeHashCode((byte[]) obj);
374                        }
375                        if (obj instanceof char[]) {
376                                return nullSafeHashCode((char[]) obj);
377                        }
378                        if (obj instanceof double[]) {
379                                return nullSafeHashCode((double[]) obj);
380                        }
381                        if (obj instanceof float[]) {
382                                return nullSafeHashCode((float[]) obj);
383                        }
384                        if (obj instanceof int[]) {
385                                return nullSafeHashCode((int[]) obj);
386                        }
387                        if (obj instanceof long[]) {
388                                return nullSafeHashCode((long[]) obj);
389                        }
390                        if (obj instanceof short[]) {
391                                return nullSafeHashCode((short[]) obj);
392                        }
393                }
394                return obj.hashCode();
395        }
396
397        /**
398         * Return a hash code based on the contents of the specified array.
399         * If {@code array} is {@code null}, this method returns 0.
400         */
401        public static int nullSafeHashCode(Object[] array) {
402                if (array == null) {
403                        return 0;
404                }
405                int hash = INITIAL_HASH;
406                for (Object element : array) {
407                        hash = MULTIPLIER * hash + nullSafeHashCode(element);
408                }
409                return hash;
410        }
411
412        /**
413         * Return a hash code based on the contents of the specified array.
414         * If {@code array} is {@code null}, this method returns 0.
415         */
416        public static int nullSafeHashCode(boolean[] array) {
417                if (array == null) {
418                        return 0;
419                }
420                int hash = INITIAL_HASH;
421                for (boolean element : array) {
422                        hash = MULTIPLIER * hash + hashCode(element);
423                }
424                return hash;
425        }
426
427        /**
428         * Return a hash code based on the contents of the specified array.
429         * If {@code array} is {@code null}, this method returns 0.
430         */
431        public static int nullSafeHashCode(byte[] array) {
432                if (array == null) {
433                        return 0;
434                }
435                int hash = INITIAL_HASH;
436                for (byte element : array) {
437                        hash = MULTIPLIER * hash + element;
438                }
439                return hash;
440        }
441
442        /**
443         * Return a hash code based on the contents of the specified array.
444         * If {@code array} is {@code null}, this method returns 0.
445         */
446        public static int nullSafeHashCode(char[] array) {
447                if (array == null) {
448                        return 0;
449                }
450                int hash = INITIAL_HASH;
451                for (char element : array) {
452                        hash = MULTIPLIER * hash + element;
453                }
454                return hash;
455        }
456
457        /**
458         * Return a hash code based on the contents of the specified array.
459         * If {@code array} is {@code null}, this method returns 0.
460         */
461        public static int nullSafeHashCode(double[] array) {
462                if (array == null) {
463                        return 0;
464                }
465                int hash = INITIAL_HASH;
466                for (double element : array) {
467                        hash = MULTIPLIER * hash + hashCode(element);
468                }
469                return hash;
470        }
471
472        /**
473         * Return a hash code based on the contents of the specified array.
474         * If {@code array} is {@code null}, this method returns 0.
475         */
476        public static int nullSafeHashCode(float[] array) {
477                if (array == null) {
478                        return 0;
479                }
480                int hash = INITIAL_HASH;
481                for (float element : array) {
482                        hash = MULTIPLIER * hash + hashCode(element);
483                }
484                return hash;
485        }
486
487        /**
488         * Return a hash code based on the contents of the specified array.
489         * If {@code array} is {@code null}, this method returns 0.
490         */
491        public static int nullSafeHashCode(int[] array) {
492                if (array == null) {
493                        return 0;
494                }
495                int hash = INITIAL_HASH;
496                for (int element : array) {
497                        hash = MULTIPLIER * hash + element;
498                }
499                return hash;
500        }
501
502        /**
503         * Return a hash code based on the contents of the specified array.
504         * If {@code array} is {@code null}, this method returns 0.
505         */
506        public static int nullSafeHashCode(long[] array) {
507                if (array == null) {
508                        return 0;
509                }
510                int hash = INITIAL_HASH;
511                for (long element : array) {
512                        hash = MULTIPLIER * hash + hashCode(element);
513                }
514                return hash;
515        }
516
517        /**
518         * Return a hash code based on the contents of the specified array.
519         * If {@code array} is {@code null}, this method returns 0.
520         */
521        public static int nullSafeHashCode(short[] array) {
522                if (array == null) {
523                        return 0;
524                }
525                int hash = INITIAL_HASH;
526                for (short element : array) {
527                        hash = MULTIPLIER * hash + element;
528                }
529                return hash;
530        }
531
532        /**
533         * Return the same value as {@link Boolean#hashCode()}}.
534         * @see Boolean#hashCode()
535         */
536        public static int hashCode(boolean bool) {
537                return (bool ? 1231 : 1237);
538        }
539
540        /**
541         * Return the same value as {@link Double#hashCode()}}.
542         * @see Double#hashCode()
543         */
544        public static int hashCode(double dbl) {
545                return hashCode(Double.doubleToLongBits(dbl));
546        }
547
548        /**
549         * Return the same value as {@link Float#hashCode()}}.
550         * @see Float#hashCode()
551         */
552        public static int hashCode(float flt) {
553                return Float.floatToIntBits(flt);
554        }
555
556        /**
557         * Return the same value as {@link Long#hashCode()}}.
558         * @see Long#hashCode()
559         */
560        public static int hashCode(long lng) {
561                return (int) (lng ^ (lng >>> 32));
562        }
563
564
565        //---------------------------------------------------------------------
566        // Convenience methods for toString output
567        //---------------------------------------------------------------------
568
569        /**
570         * Return a String representation of an object's overall identity.
571         * @param obj the object (may be {@code null})
572         * @return the object's identity as String representation,
573         * or an empty String if the object was {@code null}
574         */
575        public static String identityToString(Object obj) {
576                if (obj == null) {
577                        return EMPTY_STRING;
578                }
579                return obj.getClass().getName() + "@" + getIdentityHexString(obj);
580        }
581
582        /**
583         * Return a hex String form of an object's identity hash code.
584         * @param obj the object
585         * @return the object's identity code in hex notation
586         */
587        public static String getIdentityHexString(Object obj) {
588                return Integer.toHexString(System.identityHashCode(obj));
589        }
590
591        /**
592         * Return a content-based String representation if {@code obj} is
593         * not {@code null}; otherwise returns an empty String.
594         * <p>Differs from {@link #nullSafeToString(Object)} in that it returns
595         * an empty String rather than "null" for a {@code null} value.
596         * @param obj the object to build a display String for
597         * @return a display String representation of {@code obj}
598         * @see #nullSafeToString(Object)
599         */
600        public static String getDisplayString(Object obj) {
601                if (obj == null) {
602                        return EMPTY_STRING;
603                }
604                return nullSafeToString(obj);
605        }
606
607        /**
608         * Determine the class name for the given object.
609         * <p>Returns a {@code "null"} String if {@code obj} is {@code null}.
610         * @param obj the object to introspect (may be {@code null})
611         * @return the corresponding class name
612         */
613        public static String nullSafeClassName(Object obj) {
614                return (obj != null ? obj.getClass().getName() : NULL_STRING);
615        }
616
617        /**
618         * Return a String representation of the specified Object.
619         * <p>Builds a String representation of the contents in case of an array.
620         * Returns a {@code "null"} String if {@code obj} is {@code null}.
621         * @param obj the object to build a String representation for
622         * @return a String representation of {@code obj}
623         */
624        public static String nullSafeToString(Object obj) {
625                if (obj == null) {
626                        return NULL_STRING;
627                }
628                if (obj instanceof String) {
629                        return (String) obj;
630                }
631                if (obj instanceof Object[]) {
632                        return nullSafeToString((Object[]) obj);
633                }
634                if (obj instanceof boolean[]) {
635                        return nullSafeToString((boolean[]) obj);
636                }
637                if (obj instanceof byte[]) {
638                        return nullSafeToString((byte[]) obj);
639                }
640                if (obj instanceof char[]) {
641                        return nullSafeToString((char[]) obj);
642                }
643                if (obj instanceof double[]) {
644                        return nullSafeToString((double[]) obj);
645                }
646                if (obj instanceof float[]) {
647                        return nullSafeToString((float[]) obj);
648                }
649                if (obj instanceof int[]) {
650                        return nullSafeToString((int[]) obj);
651                }
652                if (obj instanceof long[]) {
653                        return nullSafeToString((long[]) obj);
654                }
655                if (obj instanceof short[]) {
656                        return nullSafeToString((short[]) obj);
657                }
658                String str = obj.toString();
659                return (str != null ? str : EMPTY_STRING);
660        }
661
662        /**
663         * Return a String representation of the contents of the specified array.
664         * <p>The String representation consists of a list of the array's elements,
665         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
666         * by the characters {@code ", "} (a comma followed by a space).
667         * Returns a {@code "null"} String if {@code array} is {@code null}.
668         * @param array the array to build a String representation for
669         * @return a String representation of {@code array}
670         */
671        public static String nullSafeToString(Object[] array) {
672                if (array == null) {
673                        return NULL_STRING;
674                }
675                int length = array.length;
676                if (length == 0) {
677                        return EMPTY_ARRAY;
678                }
679                StringBuilder sb = new StringBuilder();
680                for (int i = 0; i < length; i++) {
681                        if (i == 0) {
682                                sb.append(ARRAY_START);
683                        }
684                        else {
685                                sb.append(ARRAY_ELEMENT_SEPARATOR);
686                        }
687                        sb.append(String.valueOf(array[i]));
688                }
689                sb.append(ARRAY_END);
690                return sb.toString();
691        }
692
693        /**
694         * Return a String representation of the contents of the specified array.
695         * <p>The String representation consists of a list of the array's elements,
696         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
697         * by the characters {@code ", "} (a comma followed by a space).
698         * Returns a {@code "null"} String if {@code array} is {@code null}.
699         * @param array the array to build a String representation for
700         * @return a String representation of {@code array}
701         */
702        public static String nullSafeToString(boolean[] array) {
703                if (array == null) {
704                        return NULL_STRING;
705                }
706                int length = array.length;
707                if (length == 0) {
708                        return EMPTY_ARRAY;
709                }
710                StringBuilder sb = new StringBuilder();
711                for (int i = 0; i < length; i++) {
712                        if (i == 0) {
713                                sb.append(ARRAY_START);
714                        }
715                        else {
716                                sb.append(ARRAY_ELEMENT_SEPARATOR);
717                        }
718
719                        sb.append(array[i]);
720                }
721                sb.append(ARRAY_END);
722                return sb.toString();
723        }
724
725        /**
726         * Return a String representation of the contents of the specified array.
727         * <p>The String representation consists of a list of the array's elements,
728         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
729         * by the characters {@code ", "} (a comma followed by a space).
730         * Returns a {@code "null"} String if {@code array} is {@code null}.
731         * @param array the array to build a String representation for
732         * @return a String representation of {@code array}
733         */
734        public static String nullSafeToString(byte[] array) {
735                if (array == null) {
736                        return NULL_STRING;
737                }
738                int length = array.length;
739                if (length == 0) {
740                        return EMPTY_ARRAY;
741                }
742                StringBuilder sb = new StringBuilder();
743                for (int i = 0; i < length; i++) {
744                        if (i == 0) {
745                                sb.append(ARRAY_START);
746                        }
747                        else {
748                                sb.append(ARRAY_ELEMENT_SEPARATOR);
749                        }
750                        sb.append(array[i]);
751                }
752                sb.append(ARRAY_END);
753                return sb.toString();
754        }
755
756        /**
757         * Return a String representation of the contents of the specified array.
758         * <p>The String representation consists of a list of the array's elements,
759         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
760         * by the characters {@code ", "} (a comma followed by a space).
761         * Returns a {@code "null"} String if {@code array} is {@code null}.
762         * @param array the array to build a String representation for
763         * @return a String representation of {@code array}
764         */
765        public static String nullSafeToString(char[] array) {
766                if (array == null) {
767                        return NULL_STRING;
768                }
769                int length = array.length;
770                if (length == 0) {
771                        return EMPTY_ARRAY;
772                }
773                StringBuilder sb = new StringBuilder();
774                for (int i = 0; i < length; i++) {
775                        if (i == 0) {
776                                sb.append(ARRAY_START);
777                        }
778                        else {
779                                sb.append(ARRAY_ELEMENT_SEPARATOR);
780                        }
781                        sb.append("'").append(array[i]).append("'");
782                }
783                sb.append(ARRAY_END);
784                return sb.toString();
785        }
786
787        /**
788         * Return a String representation of the contents of the specified array.
789         * <p>The String representation consists of a list of the array's elements,
790         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
791         * by the characters {@code ", "} (a comma followed by a space).
792         * Returns a {@code "null"} String if {@code array} is {@code null}.
793         * @param array the array to build a String representation for
794         * @return a String representation of {@code array}
795         */
796        public static String nullSafeToString(double[] array) {
797                if (array == null) {
798                        return NULL_STRING;
799                }
800                int length = array.length;
801                if (length == 0) {
802                        return EMPTY_ARRAY;
803                }
804                StringBuilder sb = new StringBuilder();
805                for (int i = 0; i < length; i++) {
806                        if (i == 0) {
807                                sb.append(ARRAY_START);
808                        }
809                        else {
810                                sb.append(ARRAY_ELEMENT_SEPARATOR);
811                        }
812
813                        sb.append(array[i]);
814                }
815                sb.append(ARRAY_END);
816                return sb.toString();
817        }
818
819        /**
820         * Return a String representation of the contents of the specified array.
821         * <p>The String representation consists of a list of the array's elements,
822         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
823         * by the characters {@code ", "} (a comma followed by a space).
824         * Returns a {@code "null"} String if {@code array} is {@code null}.
825         * @param array the array to build a String representation for
826         * @return a String representation of {@code array}
827         */
828        public static String nullSafeToString(float[] array) {
829                if (array == null) {
830                        return NULL_STRING;
831                }
832                int length = array.length;
833                if (length == 0) {
834                        return EMPTY_ARRAY;
835                }
836                StringBuilder sb = new StringBuilder();
837                for (int i = 0; i < length; i++) {
838                        if (i == 0) {
839                                sb.append(ARRAY_START);
840                        }
841                        else {
842                                sb.append(ARRAY_ELEMENT_SEPARATOR);
843                        }
844
845                        sb.append(array[i]);
846                }
847                sb.append(ARRAY_END);
848                return sb.toString();
849        }
850
851        /**
852         * Return a String representation of the contents of the specified array.
853         * <p>The String representation consists of a list of the array's elements,
854         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
855         * by the characters {@code ", "} (a comma followed by a space).
856         * Returns a {@code "null"} String if {@code array} is {@code null}.
857         * @param array the array to build a String representation for
858         * @return a String representation of {@code array}
859         */
860        public static String nullSafeToString(int[] array) {
861                if (array == null) {
862                        return NULL_STRING;
863                }
864                int length = array.length;
865                if (length == 0) {
866                        return EMPTY_ARRAY;
867                }
868                StringBuilder sb = new StringBuilder();
869                for (int i = 0; i < length; i++) {
870                        if (i == 0) {
871                                sb.append(ARRAY_START);
872                        }
873                        else {
874                                sb.append(ARRAY_ELEMENT_SEPARATOR);
875                        }
876                        sb.append(array[i]);
877                }
878                sb.append(ARRAY_END);
879                return sb.toString();
880        }
881
882        /**
883         * Return a String representation of the contents of the specified array.
884         * <p>The String representation consists of a list of the array's elements,
885         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
886         * by the characters {@code ", "} (a comma followed by a space).
887         * Returns a {@code "null"} String if {@code array} is {@code null}.
888         * @param array the array to build a String representation for
889         * @return a String representation of {@code array}
890         */
891        public static String nullSafeToString(long[] array) {
892                if (array == null) {
893                        return NULL_STRING;
894                }
895                int length = array.length;
896                if (length == 0) {
897                        return EMPTY_ARRAY;
898                }
899                StringBuilder sb = new StringBuilder();
900                for (int i = 0; i < length; i++) {
901                        if (i == 0) {
902                                sb.append(ARRAY_START);
903                        }
904                        else {
905                                sb.append(ARRAY_ELEMENT_SEPARATOR);
906                        }
907                        sb.append(array[i]);
908                }
909                sb.append(ARRAY_END);
910                return sb.toString();
911        }
912
913        /**
914         * Return a String representation of the contents of the specified array.
915         * <p>The String representation consists of a list of the array's elements,
916         * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated
917         * by the characters {@code ", "} (a comma followed by a space).
918         * Returns a {@code "null"} String if {@code array} is {@code null}.
919         * @param array the array to build a String representation for
920         * @return a String representation of {@code array}
921         */
922        public static String nullSafeToString(short[] array) {
923                if (array == null) {
924                        return NULL_STRING;
925                }
926                int length = array.length;
927                if (length == 0) {
928                        return EMPTY_ARRAY;
929                }
930                StringBuilder sb = new StringBuilder();
931                for (int i = 0; i < length; i++) {
932                        if (i == 0) {
933                                sb.append(ARRAY_START);
934                        }
935                        else {
936                                sb.append(ARRAY_ELEMENT_SEPARATOR);
937                        }
938                        sb.append(array[i]);
939                }
940                sb.append(ARRAY_END);
941                return sb.toString();
942        }
943
944}