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 * () -> "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 > 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 > 0, () -> "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, () -> "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 * () -> "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 * () -> "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 * () -> "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, () -> "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, () -> "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, () -> "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, () -> "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, () -> "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, () -> "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, () -> "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, () -> "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}