001/*
002 * Copyright 2002-2020 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.util.Collection;
020import java.util.Map;
021import java.util.function.Supplier;
022
023import org.springframework.lang.Nullable;
024
025/**
026 * Assertion utility class that assists in validating arguments.
027 *
028 * <p>Useful for identifying programmer errors early and clearly at runtime.
029 *
030 * <p>For example, if the contract of a public method states it does not
031 * allow {@code null} arguments, {@code Assert} can be used to validate that
032 * contract. Doing this clearly indicates a contract violation when it
033 * occurs and protects the class's invariants.
034 *
035 * <p>Typically used to validate method arguments rather than configuration
036 * properties, to check for cases that are usually programmer errors rather
037 * than configuration errors. In contrast to configuration initialization
038 * code, there is usually no point in falling back to defaults in such methods.
039 *
040 * <p>This class is similar to JUnit's assertion library. If an argument value is
041 * deemed invalid, an {@link IllegalArgumentException} is thrown (typically).
042 * For example:
043 *
044 * <pre class="code">
045 * Assert.notNull(clazz, "The class must not be null");
046 * Assert.isTrue(i > 0, "The value must be greater than zero");</pre>
047 *
048 * <p>Mainly for internal use within the framework; for a more comprehensive suite
049 * of assertion utilities consider {@code org.apache.commons.lang3.Validate} from
050 * <a href="https://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a>,
051 * Google Guava's
052 * <a href="https://github.com/google/guava/wiki/PreconditionsExplained">Preconditions</a>,
053 * or similar third-party libraries.
054 *
055 * @author Keith Donald
056 * @author Juergen Hoeller
057 * @author Sam Brannen
058 * @author Colin Sampaleanu
059 * @author Rob Harrop
060 * @since 1.1.2
061 */
062public abstract class Assert {
063
064        /**
065         * Assert a boolean expression, throwing an {@code IllegalStateException}
066         * if the expression evaluates to {@code false}.
067         * <p>Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException}
068         * on an assertion failure.
069         * <pre class="code">Assert.state(id == null, "The id property must not already be initialized");</pre>
070         * @param expression a boolean expression
071         * @param message the exception message to use if the assertion fails
072         * @throws IllegalStateException if {@code expression} is {@code false}
073         */
074        public static void state(boolean expression, String message) {
075                if (!expression) {
076                        throw new IllegalStateException(message);
077                }
078        }
079
080        /**
081         * Assert a boolean expression, throwing an {@code IllegalStateException}
082         * if the expression evaluates to {@code false}.
083         * <p>Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException}
084         * on an assertion failure.
085         * <pre class="code">
086         * Assert.state(entity.getId() == null,
087         *     () -&gt; "ID for entity " + entity.getName() + " must not already be initialized");
088         * </pre>
089         * @param expression a boolean expression
090         * @param messageSupplier a supplier for the exception message to use if the
091         * assertion fails
092         * @throws IllegalStateException if {@code expression} is {@code false}
093         * @since 5.0
094         */
095        public static void state(boolean expression, Supplier<String> messageSupplier) {
096                if (!expression) {
097                        throw new IllegalStateException(nullSafeGet(messageSupplier));
098                }
099        }
100
101        /**
102         * Assert a boolean expression, throwing an {@code IllegalStateException}
103         * if the expression evaluates to {@code false}.
104         * @deprecated as of 4.3.7, in favor of {@link #state(boolean, String)}
105         */
106        @Deprecated
107        public static void state(boolean expression) {
108                state(expression, "[Assertion failed] - this state invariant must be true");
109        }
110
111        /**
112         * Assert a boolean expression, throwing an {@code IllegalArgumentException}
113         * if the expression evaluates to {@code false}.
114         * <pre class="code">Assert.isTrue(i &gt; 0, "The value must be greater than zero");</pre>
115         * @param expression a boolean expression
116         * @param message the exception message to use if the assertion fails
117         * @throws IllegalArgumentException if {@code expression} is {@code false}
118         */
119        public static void isTrue(boolean expression, String message) {
120                if (!expression) {
121                        throw new IllegalArgumentException(message);
122                }
123        }
124
125        /**
126         * Assert a boolean expression, throwing an {@code IllegalArgumentException}
127         * if the expression evaluates to {@code false}.
128         * <pre class="code">
129         * Assert.isTrue(i &gt; 0, () -&gt; "The value '" + i + "' must be greater than zero");
130         * </pre>
131         * @param expression a boolean expression
132         * @param messageSupplier a supplier for the exception message to use if the
133         * assertion fails
134         * @throws IllegalArgumentException if {@code expression} is {@code false}
135         * @since 5.0
136         */
137        public static void isTrue(boolean expression, Supplier<String> messageSupplier) {
138                if (!expression) {
139                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
140                }
141        }
142
143        /**
144         * Assert a boolean expression, throwing an {@code IllegalArgumentException}
145         * if the expression evaluates to {@code false}.
146         * @deprecated as of 4.3.7, in favor of {@link #isTrue(boolean, String)}
147         */
148        @Deprecated
149        public static void isTrue(boolean expression) {
150                isTrue(expression, "[Assertion failed] - this expression must be true");
151        }
152
153        /**
154         * Assert that an object is {@code null}.
155         * <pre class="code">Assert.isNull(value, "The value must be null");</pre>
156         * @param object the object to check
157         * @param message the exception message to use if the assertion fails
158         * @throws IllegalArgumentException if the object is not {@code null}
159         */
160        public static void isNull(@Nullable Object object, String message) {
161                if (object != null) {
162                        throw new IllegalArgumentException(message);
163                }
164        }
165
166        /**
167         * Assert that an object is {@code null}.
168         * <pre class="code">
169         * Assert.isNull(value, () -&gt; "The value '" + value + "' must be null");
170         * </pre>
171         * @param object the object to check
172         * @param messageSupplier a supplier for the exception message to use if the
173         * assertion fails
174         * @throws IllegalArgumentException if the object is not {@code null}
175         * @since 5.0
176         */
177        public static void isNull(@Nullable Object object, Supplier<String> messageSupplier) {
178                if (object != null) {
179                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
180                }
181        }
182
183        /**
184         * Assert that an object is {@code null}.
185         * @deprecated as of 4.3.7, in favor of {@link #isNull(Object, String)}
186         */
187        @Deprecated
188        public static void isNull(@Nullable Object object) {
189                isNull(object, "[Assertion failed] - the object argument must be null");
190        }
191
192        /**
193         * Assert that an object is not {@code null}.
194         * <pre class="code">Assert.notNull(clazz, "The class must not be null");</pre>
195         * @param object the object to check
196         * @param message the exception message to use if the assertion fails
197         * @throws IllegalArgumentException if the object is {@code null}
198         */
199        public static void notNull(@Nullable Object object, String message) {
200                if (object == null) {
201                        throw new IllegalArgumentException(message);
202                }
203        }
204
205        /**
206         * Assert that an object is not {@code null}.
207         * <pre class="code">
208         * Assert.notNull(entity.getId(),
209         *     () -&gt; "ID for entity " + entity.getName() + " must not be null");
210         * </pre>
211         * @param object the object to check
212         * @param messageSupplier a supplier for the exception message to use if the
213         * assertion fails
214         * @throws IllegalArgumentException if the object is {@code null}
215         * @since 5.0
216         */
217        public static void notNull(@Nullable Object object, Supplier<String> messageSupplier) {
218                if (object == null) {
219                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
220                }
221        }
222
223        /**
224         * Assert that an object is not {@code null}.
225         * @deprecated as of 4.3.7, in favor of {@link #notNull(Object, String)}
226         */
227        @Deprecated
228        public static void notNull(@Nullable Object object) {
229                notNull(object, "[Assertion failed] - this argument is required; it must not be null");
230        }
231
232        /**
233         * Assert that the given String is not empty; that is,
234         * it must not be {@code null} and not the empty String.
235         * <pre class="code">Assert.hasLength(name, "Name must not be empty");</pre>
236         * @param text the String to check
237         * @param message the exception message to use if the assertion fails
238         * @throws IllegalArgumentException if the text is empty
239         * @see StringUtils#hasLength
240         */
241        public static void hasLength(@Nullable String text, String message) {
242                if (!StringUtils.hasLength(text)) {
243                        throw new IllegalArgumentException(message);
244                }
245        }
246
247        /**
248         * Assert that the given String is not empty; that is,
249         * it must not be {@code null} and not the empty String.
250         * <pre class="code">
251         * Assert.hasLength(account.getName(),
252         *     () -&gt; "Name for account '" + account.getId() + "' must not be empty");
253         * </pre>
254         * @param text the String to check
255         * @param messageSupplier a supplier for the exception message to use if the
256         * assertion fails
257         * @throws IllegalArgumentException if the text is empty
258         * @since 5.0
259         * @see StringUtils#hasLength
260         */
261        public static void hasLength(@Nullable String text, Supplier<String> messageSupplier) {
262                if (!StringUtils.hasLength(text)) {
263                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
264                }
265        }
266
267        /**
268         * Assert that the given String is not empty; that is,
269         * it must not be {@code null} and not the empty String.
270         * @deprecated as of 4.3.7, in favor of {@link #hasLength(String, String)}
271         */
272        @Deprecated
273        public static void hasLength(@Nullable String text) {
274                hasLength(text,
275                                "[Assertion failed] - this String argument must have length; it must not be null or empty");
276        }
277
278        /**
279         * Assert that the given String contains valid text content; that is, it must not
280         * be {@code null} and must contain at least one non-whitespace character.
281         * <pre class="code">Assert.hasText(name, "'name' must not be empty");</pre>
282         * @param text the String to check
283         * @param message the exception message to use if the assertion fails
284         * @throws IllegalArgumentException if the text does not contain valid text content
285         * @see StringUtils#hasText
286         */
287        public static void hasText(@Nullable String text, String message) {
288                if (!StringUtils.hasText(text)) {
289                        throw new IllegalArgumentException(message);
290                }
291        }
292
293        /**
294         * Assert that the given String contains valid text content; that is, it must not
295         * be {@code null} and must contain at least one non-whitespace character.
296         * <pre class="code">
297         * Assert.hasText(account.getName(),
298         *     () -&gt; "Name for account '" + account.getId() + "' must not be empty");
299         * </pre>
300         * @param text the String to check
301         * @param messageSupplier a supplier for the exception message to use if the
302         * assertion fails
303         * @throws IllegalArgumentException if the text does not contain valid text content
304         * @since 5.0
305         * @see StringUtils#hasText
306         */
307        public static void hasText(@Nullable String text, Supplier<String> messageSupplier) {
308                if (!StringUtils.hasText(text)) {
309                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
310                }
311        }
312
313        /**
314         * Assert that the given String contains valid text content; that is, it must not
315         * be {@code null} and must contain at least one non-whitespace character.
316         * @deprecated as of 4.3.7, in favor of {@link #hasText(String, String)}
317         */
318        @Deprecated
319        public static void hasText(@Nullable String text) {
320                hasText(text,
321                                "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
322        }
323
324        /**
325         * Assert that the given text does not contain the given substring.
326         * <pre class="code">Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");</pre>
327         * @param textToSearch the text to search
328         * @param substring the substring to find within the text
329         * @param message the exception message to use if the assertion fails
330         * @throws IllegalArgumentException if the text contains the substring
331         */
332        public static void doesNotContain(@Nullable String textToSearch, String substring, String message) {
333                if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
334                                textToSearch.contains(substring)) {
335                        throw new IllegalArgumentException(message);
336                }
337        }
338
339        /**
340         * Assert that the given text does not contain the given substring.
341         * <pre class="code">
342         * Assert.doesNotContain(name, forbidden, () -&gt; "Name must not contain '" + forbidden + "'");
343         * </pre>
344         * @param textToSearch the text to search
345         * @param substring the substring to find within the text
346         * @param messageSupplier a supplier for the exception message to use if the
347         * assertion fails
348         * @throws IllegalArgumentException if the text contains the substring
349         * @since 5.0
350         */
351        public static void doesNotContain(@Nullable String textToSearch, String substring, Supplier<String> messageSupplier) {
352                if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
353                                textToSearch.contains(substring)) {
354                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
355                }
356        }
357
358        /**
359         * Assert that the given text does not contain the given substring.
360         * @deprecated as of 4.3.7, in favor of {@link #doesNotContain(String, String, String)}
361         */
362        @Deprecated
363        public static void doesNotContain(@Nullable String textToSearch, String substring) {
364                doesNotContain(textToSearch, substring,
365                                () -> "[Assertion failed] - this String argument must not contain the substring [" + substring + "]");
366        }
367
368        /**
369         * Assert that an array contains elements; that is, it must not be
370         * {@code null} and must contain at least one element.
371         * <pre class="code">Assert.notEmpty(array, "The array must contain elements");</pre>
372         * @param array the array to check
373         * @param message the exception message to use if the assertion fails
374         * @throws IllegalArgumentException if the object array is {@code null} or contains no elements
375         */
376        public static void notEmpty(@Nullable Object[] array, String message) {
377                if (ObjectUtils.isEmpty(array)) {
378                        throw new IllegalArgumentException(message);
379                }
380        }
381
382        /**
383         * Assert that an array contains elements; that is, it must not be
384         * {@code null} and must contain at least one element.
385         * <pre class="code">
386         * Assert.notEmpty(array, () -&gt; "The " + arrayType + " array must contain elements");
387         * </pre>
388         * @param array the array to check
389         * @param messageSupplier a supplier for the exception message to use if the
390         * assertion fails
391         * @throws IllegalArgumentException if the object array is {@code null} or contains no elements
392         * @since 5.0
393         */
394        public static void notEmpty(@Nullable Object[] array, Supplier<String> messageSupplier) {
395                if (ObjectUtils.isEmpty(array)) {
396                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
397                }
398        }
399
400        /**
401         * Assert that an array contains elements; that is, it must not be
402         * {@code null} and must contain at least one element.
403         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Object[], String)}
404         */
405        @Deprecated
406        public static void notEmpty(@Nullable Object[] array) {
407                notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
408        }
409
410        /**
411         * Assert that an array contains no {@code null} elements.
412         * <p>Note: Does not complain if the array is empty!
413         * <pre class="code">Assert.noNullElements(array, "The array must contain non-null elements");</pre>
414         * @param array the array to check
415         * @param message the exception message to use if the assertion fails
416         * @throws IllegalArgumentException if the object array contains a {@code null} element
417         */
418        public static void noNullElements(@Nullable Object[] array, String message) {
419                if (array != null) {
420                        for (Object element : array) {
421                                if (element == null) {
422                                        throw new IllegalArgumentException(message);
423                                }
424                        }
425                }
426        }
427
428        /**
429         * Assert that an array contains no {@code null} elements.
430         * <p>Note: Does not complain if the array is empty!
431         * <pre class="code">
432         * Assert.noNullElements(array, () -&gt; "The " + arrayType + " array must contain non-null elements");
433         * </pre>
434         * @param array the array to check
435         * @param messageSupplier a supplier for the exception message to use if the
436         * assertion fails
437         * @throws IllegalArgumentException if the object array contains a {@code null} element
438         * @since 5.0
439         */
440        public static void noNullElements(@Nullable Object[] array, Supplier<String> messageSupplier) {
441                if (array != null) {
442                        for (Object element : array) {
443                                if (element == null) {
444                                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
445                                }
446                        }
447                }
448        }
449
450        /**
451         * Assert that an array contains no {@code null} elements.
452         * @deprecated as of 4.3.7, in favor of {@link #noNullElements(Object[], String)}
453         */
454        @Deprecated
455        public static void noNullElements(@Nullable Object[] array) {
456                noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
457        }
458
459        /**
460         * Assert that a collection contains elements; that is, it must not be
461         * {@code null} and must contain at least one element.
462         * <pre class="code">Assert.notEmpty(collection, "Collection must contain elements");</pre>
463         * @param collection the collection to check
464         * @param message the exception message to use if the assertion fails
465         * @throws IllegalArgumentException if the collection is {@code null} or
466         * contains no elements
467         */
468        public static void notEmpty(@Nullable Collection<?> collection, String message) {
469                if (CollectionUtils.isEmpty(collection)) {
470                        throw new IllegalArgumentException(message);
471                }
472        }
473
474        /**
475         * Assert that a collection contains elements; that is, it must not be
476         * {@code null} and must contain at least one element.
477         * <pre class="code">
478         * Assert.notEmpty(collection, () -&gt; "The " + collectionType + " collection must contain elements");
479         * </pre>
480         * @param collection the collection to check
481         * @param messageSupplier a supplier for the exception message to use if the
482         * assertion fails
483         * @throws IllegalArgumentException if the collection is {@code null} or
484         * contains no elements
485         * @since 5.0
486         */
487        public static void notEmpty(@Nullable Collection<?> collection, Supplier<String> messageSupplier) {
488                if (CollectionUtils.isEmpty(collection)) {
489                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
490                }
491        }
492
493        /**
494         * Assert that a collection contains elements; that is, it must not be
495         * {@code null} and must contain at least one element.
496         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Collection, String)}
497         */
498        @Deprecated
499        public static void notEmpty(@Nullable Collection<?> collection) {
500                notEmpty(collection,
501                                "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
502        }
503
504        /**
505         * Assert that a collection contains no {@code null} elements.
506         * <p>Note: Does not complain if the collection is empty!
507         * <pre class="code">Assert.noNullElements(collection, "Collection must contain non-null elements");</pre>
508         * @param collection the collection to check
509         * @param message the exception message to use if the assertion fails
510         * @throws IllegalArgumentException if the collection contains a {@code null} element
511         * @since 5.2
512         */
513        public static void noNullElements(@Nullable Collection<?> collection, String message) {
514                if (collection != null) {
515                        for (Object element : collection) {
516                                if (element == null) {
517                                        throw new IllegalArgumentException(message);
518                                }
519                        }
520                }
521        }
522
523        /**
524         * Assert that a collection contains no {@code null} elements.
525         * <p>Note: Does not complain if the collection is empty!
526         * <pre class="code">
527         * Assert.noNullElements(collection, () -&gt; "Collection " + collectionName + " must contain non-null elements");
528         * </pre>
529         * @param collection the collection to check
530         * @param messageSupplier a supplier for the exception message to use if the
531         * assertion fails
532         * @throws IllegalArgumentException if the collection contains a {@code null} element
533         * @since 5.2
534         */
535        public static void noNullElements(@Nullable Collection<?> collection, Supplier<String> messageSupplier) {
536                if (collection != null) {
537                        for (Object element : collection) {
538                                if (element == null) {
539                                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
540                                }
541                        }
542                }
543        }
544
545        /**
546         * Assert that a Map contains entries; that is, it must not be {@code null}
547         * and must contain at least one entry.
548         * <pre class="code">Assert.notEmpty(map, "Map must contain entries");</pre>
549         * @param map the map to check
550         * @param message the exception message to use if the assertion fails
551         * @throws IllegalArgumentException if the map is {@code null} or contains no entries
552         */
553        public static void notEmpty(@Nullable Map<?, ?> map, String message) {
554                if (CollectionUtils.isEmpty(map)) {
555                        throw new IllegalArgumentException(message);
556                }
557        }
558
559        /**
560         * Assert that a Map contains entries; that is, it must not be {@code null}
561         * and must contain at least one entry.
562         * <pre class="code">
563         * Assert.notEmpty(map, () -&gt; "The " + mapType + " map must contain entries");
564         * </pre>
565         * @param map the map to check
566         * @param messageSupplier a supplier for the exception message to use if the
567         * assertion fails
568         * @throws IllegalArgumentException if the map is {@code null} or contains no entries
569         * @since 5.0
570         */
571        public static void notEmpty(@Nullable Map<?, ?> map, Supplier<String> messageSupplier) {
572                if (CollectionUtils.isEmpty(map)) {
573                        throw new IllegalArgumentException(nullSafeGet(messageSupplier));
574                }
575        }
576
577        /**
578         * Assert that a Map contains entries; that is, it must not be {@code null}
579         * and must contain at least one entry.
580         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Map, String)}
581         */
582        @Deprecated
583        public static void notEmpty(@Nullable Map<?, ?> map) {
584                notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
585        }
586
587        /**
588         * Assert that the provided object is an instance of the provided class.
589         * <pre class="code">Assert.instanceOf(Foo.class, foo, "Foo expected");</pre>
590         * @param type the type to check against
591         * @param obj the object to check
592         * @param message a message which will be prepended to provide further context.
593         * If it is empty or ends in ":" or ";" or "," or ".", a full exception message
594         * will be appended. If it ends in a space, the name of the offending object's
595         * type will be appended. In any other case, a ":" with a space and the name
596         * of the offending object's type will be appended.
597         * @throws IllegalArgumentException if the object is not an instance of type
598         */
599        public static void isInstanceOf(Class<?> type, @Nullable Object obj, String message) {
600                notNull(type, "Type to check against must not be null");
601                if (!type.isInstance(obj)) {
602                        instanceCheckFailed(type, obj, message);
603                }
604        }
605
606        /**
607         * Assert that the provided object is an instance of the provided class.
608         * <pre class="code">
609         * Assert.instanceOf(Foo.class, foo, () -&gt; "Processing " + Foo.class.getSimpleName() + ":");
610         * </pre>
611         * @param type the type to check against
612         * @param obj the object to check
613         * @param messageSupplier a supplier for the exception message to use if the
614         * assertion fails. See {@link #isInstanceOf(Class, Object, String)} for details.
615         * @throws IllegalArgumentException if the object is not an instance of type
616         * @since 5.0
617         */
618        public static void isInstanceOf(Class<?> type, @Nullable Object obj, Supplier<String> messageSupplier) {
619                notNull(type, "Type to check against must not be null");
620                if (!type.isInstance(obj)) {
621                        instanceCheckFailed(type, obj, nullSafeGet(messageSupplier));
622                }
623        }
624
625        /**
626         * Assert that the provided object is an instance of the provided class.
627         * <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
628         * @param type the type to check against
629         * @param obj the object to check
630         * @throws IllegalArgumentException if the object is not an instance of type
631         */
632        public static void isInstanceOf(Class<?> type, @Nullable Object obj) {
633                isInstanceOf(type, obj, "");
634        }
635
636        /**
637         * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
638         * <pre class="code">Assert.isAssignable(Number.class, myClass, "Number expected");</pre>
639         * @param superType the super type to check against
640         * @param subType the sub type to check
641         * @param message a message which will be prepended to provide further context.
642         * If it is empty or ends in ":" or ";" or "," or ".", a full exception message
643         * will be appended. If it ends in a space, the name of the offending sub type
644         * will be appended. In any other case, a ":" with a space and the name of the
645         * offending sub type will be appended.
646         * @throws IllegalArgumentException if the classes are not assignable
647         */
648        public static void isAssignable(Class<?> superType, @Nullable Class<?> subType, String message) {
649                notNull(superType, "Super type to check against must not be null");
650                if (subType == null || !superType.isAssignableFrom(subType)) {
651                        assignableCheckFailed(superType, subType, message);
652                }
653        }
654
655        /**
656         * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
657         * <pre class="code">
658         * Assert.isAssignable(Number.class, myClass, () -&gt; "Processing " + myAttributeName + ":");
659         * </pre>
660         * @param superType the super type to check against
661         * @param subType the sub type to check
662         * @param messageSupplier a supplier for the exception message to use if the
663         * assertion fails. See {@link #isAssignable(Class, Class, String)} for details.
664         * @throws IllegalArgumentException if the classes are not assignable
665         * @since 5.0
666         */
667        public static void isAssignable(Class<?> superType, @Nullable Class<?> subType, Supplier<String> messageSupplier) {
668                notNull(superType, "Super type to check against must not be null");
669                if (subType == null || !superType.isAssignableFrom(subType)) {
670                        assignableCheckFailed(superType, subType, nullSafeGet(messageSupplier));
671                }
672        }
673
674        /**
675         * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
676         * <pre class="code">Assert.isAssignable(Number.class, myClass);</pre>
677         * @param superType the super type to check
678         * @param subType the sub type to check
679         * @throws IllegalArgumentException if the classes are not assignable
680         */
681        public static void isAssignable(Class<?> superType, Class<?> subType) {
682                isAssignable(superType, subType, "");
683        }
684
685
686        private static void instanceCheckFailed(Class<?> type, @Nullable Object obj, @Nullable String msg) {
687                String className = (obj != null ? obj.getClass().getName() : "null");
688                String result = "";
689                boolean defaultMessage = true;
690                if (StringUtils.hasLength(msg)) {
691                        if (endsWithSeparator(msg)) {
692                                result = msg + " ";
693                        }
694                        else {
695                                result = messageWithTypeName(msg, className);
696                                defaultMessage = false;
697                        }
698                }
699                if (defaultMessage) {
700                        result = result + ("Object of class [" + className + "] must be an instance of " + type);
701                }
702                throw new IllegalArgumentException(result);
703        }
704
705        private static void assignableCheckFailed(Class<?> superType, @Nullable Class<?> subType, @Nullable String msg) {
706                String result = "";
707                boolean defaultMessage = true;
708                if (StringUtils.hasLength(msg)) {
709                        if (endsWithSeparator(msg)) {
710                                result = msg + " ";
711                        }
712                        else {
713                                result = messageWithTypeName(msg, subType);
714                                defaultMessage = false;
715                        }
716                }
717                if (defaultMessage) {
718                        result = result + (subType + " is not assignable to " + superType);
719                }
720                throw new IllegalArgumentException(result);
721        }
722
723        private static boolean endsWithSeparator(String msg) {
724                return (msg.endsWith(":") || msg.endsWith(";") || msg.endsWith(",") || msg.endsWith("."));
725        }
726
727        private static String messageWithTypeName(String msg, @Nullable Object typeName) {
728                return msg + (msg.endsWith(" ") ? "" : ": ") + typeName;
729        }
730
731        @Nullable
732        private static String nullSafeGet(@Nullable Supplier<String> messageSupplier) {
733                return (messageSupplier != null ? messageSupplier.get() : null);
734        }
735
736}