001/*
002 * Copyright 2002-2017 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;
021
022/**
023 * Assertion utility class that assists in validating arguments.
024 *
025 * <p>Useful for identifying programmer errors early and clearly at runtime.
026 *
027 * <p>For example, if the contract of a public method states it does not
028 * allow {@code null} arguments, {@code Assert} can be used to validate that
029 * contract. Doing this clearly indicates a contract violation when it
030 * occurs and protects the class's invariants.
031 *
032 * <p>Typically used to validate method arguments rather than configuration
033 * properties, to check for cases that are usually programmer errors rather
034 * than configuration errors. In contrast to configuration initialization
035 * code, there is usually no point in falling back to defaults in such methods.
036 *
037 * <p>This class is similar to JUnit's assertion library. If an argument value is
038 * deemed invalid, an {@link IllegalArgumentException} is thrown (typically).
039 * For example:
040 *
041 * <pre class="code">
042 * Assert.notNull(clazz, "The class must not be null");
043 * Assert.isTrue(i > 0, "The value must be greater than zero");</pre>
044 *
045 * <p>Mainly for internal use within the framework; consider
046 * <a href="https://commons.apache.org/proper/commons-lang/">Apache's Commons Lang</a>
047 * for a more comprehensive suite of {@code String} utilities.
048 *
049 * @author Keith Donald
050 * @author Juergen Hoeller
051 * @author Sam Brannen
052 * @author Colin Sampaleanu
053 * @author Rob Harrop
054 * @since 1.1.2
055 */
056public abstract class Assert {
057
058        /**
059         * Assert a boolean expression, throwing an {@code IllegalStateException}
060         * if the expression evaluates to {@code false}.
061         * <p>Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException}
062         * on an assertion failure.
063         * <pre class="code">Assert.state(id == null, "The id property must not already be initialized");</pre>
064         * @param expression a boolean expression
065         * @param message the exception message to use if the assertion fails
066         * @throws IllegalStateException if {@code expression} is {@code false}
067         */
068        public static void state(boolean expression, String message) {
069                if (!expression) {
070                        throw new IllegalStateException(message);
071                }
072        }
073
074        /**
075         * @deprecated as of 4.3.7, in favor of {@link #state(boolean, String)}
076         */
077        @Deprecated
078        public static void state(boolean expression) {
079                state(expression, "[Assertion failed] - this state invariant must be true");
080        }
081
082        /**
083         * Assert a boolean expression, throwing an {@code IllegalArgumentException}
084         * if the expression evaluates to {@code false}.
085         * <pre class="code">Assert.isTrue(i &gt; 0, "The value must be greater than zero");</pre>
086         * @param expression a boolean expression
087         * @param message the exception message to use if the assertion fails
088         * @throws IllegalArgumentException if {@code expression} is {@code false}
089         */
090        public static void isTrue(boolean expression, String message) {
091                if (!expression) {
092                        throw new IllegalArgumentException(message);
093                }
094        }
095
096        /**
097         * @deprecated as of 4.3.7, in favor of {@link #isTrue(boolean, String)}
098         */
099        @Deprecated
100        public static void isTrue(boolean expression) {
101                isTrue(expression, "[Assertion failed] - this expression must be true");
102        }
103
104        /**
105         * Assert that an object is {@code null}.
106         * <pre class="code">Assert.isNull(value, "The value must be null");</pre>
107         * @param object the object to check
108         * @param message the exception message to use if the assertion fails
109         * @throws IllegalArgumentException if the object is not {@code null}
110         */
111        public static void isNull(Object object, String message) {
112                if (object != null) {
113                        throw new IllegalArgumentException(message);
114                }
115        }
116
117        /**
118         * @deprecated as of 4.3.7, in favor of {@link #isNull(Object, String)}
119         */
120        @Deprecated
121        public static void isNull(Object object) {
122                isNull(object, "[Assertion failed] - the object argument must be null");
123        }
124
125        /**
126         * Assert that an object is not {@code null}.
127         * <pre class="code">Assert.notNull(clazz, "The class must not be null");</pre>
128         * @param object the object to check
129         * @param message the exception message to use if the assertion fails
130         * @throws IllegalArgumentException if the object is {@code null}
131         */
132        public static void notNull(Object object, String message) {
133                if (object == null) {
134                        throw new IllegalArgumentException(message);
135                }
136        }
137
138        /**
139         * @deprecated as of 4.3.7, in favor of {@link #notNull(Object, String)}
140         */
141        @Deprecated
142        public static void notNull(Object object) {
143                notNull(object, "[Assertion failed] - this argument is required; it must not be null");
144        }
145
146        /**
147         * Assert that the given String is not empty; that is,
148         * it must not be {@code null} and not the empty String.
149         * <pre class="code">Assert.hasLength(name, "Name must not be empty");</pre>
150         * @param text the String to check
151         * @param message the exception message to use if the assertion fails
152         * @see StringUtils#hasLength
153         * @throws IllegalArgumentException if the text is empty
154         */
155        public static void hasLength(String text, String message) {
156                if (!StringUtils.hasLength(text)) {
157                        throw new IllegalArgumentException(message);
158                }
159        }
160
161        /**
162         * @deprecated as of 4.3.7, in favor of {@link #hasLength(String, String)}
163         */
164        @Deprecated
165        public static void hasLength(String text) {
166                hasLength(text,
167                                "[Assertion failed] - this String argument must have length; it must not be null or empty");
168        }
169
170        /**
171         * Assert that the given String contains valid text content; that is, it must not
172         * be {@code null} and must contain at least one non-whitespace character.
173         * <pre class="code">Assert.hasText(name, "'name' must not be empty");</pre>
174         * @param text the String to check
175         * @param message the exception message to use if the assertion fails
176         * @see StringUtils#hasText
177         * @throws IllegalArgumentException if the text does not contain valid text content
178         */
179        public static void hasText(String text, String message) {
180                if (!StringUtils.hasText(text)) {
181                        throw new IllegalArgumentException(message);
182                }
183        }
184
185        /**
186         * @deprecated as of 4.3.7, in favor of {@link #hasText(String, String)}
187         */
188        @Deprecated
189        public static void hasText(String text) {
190                hasText(text,
191                                "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
192        }
193
194        /**
195         * Assert that the given text does not contain the given substring.
196         * <pre class="code">Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");</pre>
197         * @param textToSearch the text to search
198         * @param substring the substring to find within the text
199         * @param message the exception message to use if the assertion fails
200         * @throws IllegalArgumentException if the text contains the substring
201         */
202        public static void doesNotContain(String textToSearch, String substring, String message) {
203                if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
204                                textToSearch.contains(substring)) {
205                        throw new IllegalArgumentException(message);
206                }
207        }
208
209        /**
210         * @deprecated as of 4.3.7, in favor of {@link #doesNotContain(String, String, String)}
211         */
212        @Deprecated
213        public static void doesNotContain(String textToSearch, String substring) {
214                doesNotContain(textToSearch, substring,
215                                "[Assertion failed] - this String argument must not contain the substring [" + substring + "]");
216        }
217
218        /**
219         * Assert that an array contains elements; that is, it must not be
220         * {@code null} and must contain at least one element.
221         * <pre class="code">Assert.notEmpty(array, "The array must contain elements");</pre>
222         * @param array the array to check
223         * @param message the exception message to use if the assertion fails
224         * @throws IllegalArgumentException if the object array is {@code null} or contains no elements
225         */
226        public static void notEmpty(Object[] array, String message) {
227                if (ObjectUtils.isEmpty(array)) {
228                        throw new IllegalArgumentException(message);
229                }
230        }
231
232        /**
233         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Object[], String)}
234         */
235        @Deprecated
236        public static void notEmpty(Object[] array) {
237                notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
238        }
239
240        /**
241         * Assert that an array contains no {@code null} elements.
242         * <p>Note: Does not complain if the array is empty!
243         * <pre class="code">Assert.noNullElements(array, "The array must contain non-null elements");</pre>
244         * @param array the array to check
245         * @param message the exception message to use if the assertion fails
246         * @throws IllegalArgumentException if the object array contains a {@code null} element
247         */
248        public static void noNullElements(Object[] array, String message) {
249                if (array != null) {
250                        for (Object element : array) {
251                                if (element == null) {
252                                        throw new IllegalArgumentException(message);
253                                }
254                        }
255                }
256        }
257
258        /**
259         * @deprecated as of 4.3.7, in favor of {@link #noNullElements(Object[], String)}
260         */
261        @Deprecated
262        public static void noNullElements(Object[] array) {
263                noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
264        }
265
266        /**
267         * Assert that a collection contains elements; that is, it must not be
268         * {@code null} and must contain at least one element.
269         * <pre class="code">Assert.notEmpty(collection, "Collection must contain elements");</pre>
270         * @param collection the collection to check
271         * @param message the exception message to use if the assertion fails
272         * @throws IllegalArgumentException if the collection is {@code null} or
273         * contains no elements
274         */
275        public static void notEmpty(Collection<?> collection, String message) {
276                if (CollectionUtils.isEmpty(collection)) {
277                        throw new IllegalArgumentException(message);
278                }
279        }
280
281        /**
282         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Collection, String)}
283         */
284        @Deprecated
285        public static void notEmpty(Collection<?> collection) {
286                notEmpty(collection,
287                                "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
288        }
289
290        /**
291         * Assert that a Map contains entries; that is, it must not be {@code null}
292         * and must contain at least one entry.
293         * <pre class="code">Assert.notEmpty(map, "Map must contain entries");</pre>
294         * @param map the map to check
295         * @param message the exception message to use if the assertion fails
296         * @throws IllegalArgumentException if the map is {@code null} or contains no entries
297         */
298        public static void notEmpty(Map<?, ?> map, String message) {
299                if (CollectionUtils.isEmpty(map)) {
300                        throw new IllegalArgumentException(message);
301                }
302        }
303
304        /**
305         * @deprecated as of 4.3.7, in favor of {@link #notEmpty(Map, String)}
306         */
307        @Deprecated
308        public static void notEmpty(Map<?, ?> map) {
309                notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
310        }
311
312        /**
313         * Assert that the provided object is an instance of the provided class.
314         * <pre class="code">Assert.instanceOf(Foo.class, foo, "Foo expected");</pre>
315         * @param type the type to check against
316         * @param obj the object to check
317         * @param message a message which will be prepended to provide further context.
318         * If it is empty or ends in ":" or ";" or "," or ".", a full exception message
319         * will be appended. If it ends in a space, the name of the offending object's
320         * type will be appended. In any other case, a ":" with a space and the name
321         * of the offending object's type will be appended.
322         * @throws IllegalArgumentException if the object is not an instance of type
323         */
324        public static void isInstanceOf(Class<?> type, Object obj, String message) {
325                notNull(type, "Type to check against must not be null");
326                if (!type.isInstance(obj)) {
327                        instanceCheckFailed(type, obj, message);
328                }
329        }
330
331        /**
332         * Assert that the provided object is an instance of the provided class.
333         * <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
334         * @param type the type to check against
335         * @param obj the object to check
336         * @throws IllegalArgumentException if the object is not an instance of type
337         */
338        public static void isInstanceOf(Class<?> type, Object obj) {
339                isInstanceOf(type, obj, "");
340        }
341
342        /**
343         * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
344         * <pre class="code">Assert.isAssignable(Number.class, myClass, "Number expected");</pre>
345         * @param superType the super type to check against
346         * @param subType the sub type to check
347         * @param message a message which will be prepended to provide further context.
348         * If it is empty or ends in ":" or ";" or "," or ".", a full exception message
349         * will be appended. If it ends in a space, the name of the offending sub type
350         * will be appended. In any other case, a ":" with a space and the name of the
351         * offending sub type will be appended.
352         * @throws IllegalArgumentException if the classes are not assignable
353         */
354        public static void isAssignable(Class<?> superType, Class<?> subType, String message) {
355                notNull(superType, "Super type to check against must not be null");
356                if (subType == null || !superType.isAssignableFrom(subType)) {
357                        assignableCheckFailed(superType, subType, message);
358                }
359        }
360
361        /**
362         * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
363         * <pre class="code">Assert.isAssignable(Number.class, myClass);</pre>
364         * @param superType the super type to check
365         * @param subType the sub type to check
366         * @throws IllegalArgumentException if the classes are not assignable
367         */
368        public static void isAssignable(Class<?> superType, Class<?> subType) {
369                isAssignable(superType, subType, "");
370        }
371
372
373        private static void instanceCheckFailed(Class<?> type, Object obj, String msg) {
374                String className = (obj != null ? obj.getClass().getName() : "null");
375                String result = "";
376                boolean defaultMessage = true;
377                if (StringUtils.hasLength(msg)) {
378                        if (endsWithSeparator(msg)) {
379                                result = msg + " ";
380                        }
381                        else {
382                                result = messageWithTypeName(msg, className);
383                                defaultMessage = false;
384                        }
385                }
386                if (defaultMessage) {
387                        result = result + ("Object of class [" + className + "] must be an instance of " + type);
388                }
389                throw new IllegalArgumentException(result);
390        }
391
392        private static void assignableCheckFailed(Class<?> superType, Class<?> subType, String msg) {
393                String result = "";
394                boolean defaultMessage = true;
395                if (StringUtils.hasLength(msg)) {
396                        if (endsWithSeparator(msg)) {
397                                result = msg + " ";
398                        }
399                        else {
400                                result = messageWithTypeName(msg, subType);
401                                defaultMessage = false;
402                        }
403                }
404                if (defaultMessage) {
405                        result = result + (subType + " is not assignable to " + superType);
406                }
407                throw new IllegalArgumentException(result);
408        }
409
410        private static boolean endsWithSeparator(String msg) {
411                return (msg.endsWith(":") || msg.endsWith(";") || msg.endsWith(",") || msg.endsWith("."));
412        }
413
414        private static String messageWithTypeName(String msg, Object typeName) {
415                return msg + (msg.endsWith(" ") ? "" : ": ") + typeName;
416        }
417
418}