001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.utils; 018 019import java.util.Collection; 020 021import static org.apache.juneau.commons.utils.ThrowableUtils.*; 022import static org.apache.juneau.commons.utils.Utils.*; 023 024/** 025 * Utility methods for argument validation and assertion. 026 * 027 * <p> 028 * This class provides static utility methods for validating method arguments and throwing 029 * {@link IllegalArgumentException} when validation fails. These methods are designed to 030 * simplify common parameter validation patterns and provide consistent error messages. 031 * 032 * <h5 class='section'>Features:</h5> 033 * <ul> 034 * <li><b>Null checking:</b> Validate single or multiple arguments are not null 035 * <li><b>Boolean expressions:</b> Assert arbitrary boolean conditions with custom messages 036 * <li><b>String validation:</b> Check for null or blank strings 037 * <li><b>Type checking:</b> Validate class array types 038 * </ul> 039 * 040 * <h5 class='section'>Usage:</h5> 041 * <p class='bjava'> 042 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 043 * 044 * <jk>public</jk> <jk>void</jk> setFooBar(String <jv>foo</jv>, String <jv>bar</jv>) { 045 * <jc>// Validate multiple arguments at once</jc> 046 * <jsm>assertArgsNotNull</jsm>(<js>"foo"</js>, <jv>foo</jv>, <js>"bar"</js>, <jv>bar</jv>); 047 * 048 * <jc>// Validate custom condition</jc> 049 * <jsm>assertArg</jsm>(<jv>foo</jv>.length() > 0, <js>"Foo cannot be empty"</js>); 050 * } 051 * </p> 052 * 053 * <h5 class='section'>See Also:</h5> 054 * <ul> 055 * <li class='link'><a class="doclink" href='../../../../../index.html#juneau-commons.utils'>Overview > juneau-commons.utils</a> 056 * </ul> 057 */ 058public class AssertionUtils { 059 060 /** 061 * Throws an {@link IllegalArgumentException} if the specified expression is <jk>false</jk>. 062 * 063 * <h5 class='section'>Example:</h5> 064 * <p class='bjava'> 065 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 066 * 067 * <jk>public</jk> String setFoo(List<String> <jv>foo</jv>) { 068 * <jsm>assertArg</jsm>(<jv>foo</jv> != <jk>null</jk> && ! <jv>foo</jv>.isEmpty(), <js>"'foo' cannot be null or empty."</js>); 069 * ... 070 * } 071 * </p> 072 * 073 * @param expression The boolean expression to check. 074 * @param msg The exception message. 075 * @param args The exception message args. 076 * @throws IllegalArgumentException Constructed exception. 077 */ 078 public static final void assertArg(boolean expression, String msg, Object...args) throws IllegalArgumentException { 079 if (! expression) 080 throw illegalArg(msg, args); 081 } 082 083 /** 084 * Asserts that the given expression is <c>true</c>, throwing an {@link IllegalStateException} if it's not. 085 * 086 * <p> 087 * This method is similar to {@link #assertArg(boolean, String, Object...)} but throws an 088 * {@link IllegalStateException} instead of an {@link IllegalArgumentException}, making it suitable 089 * for state validation rather than argument validation. 090 * 091 * @param expression The expression to test. 092 * @param msg The error message format string. 093 * @param args The arguments for the error message format string. 094 * @throws IllegalStateException if the expression is <c>false</c>. 095 */ 096 public static final void assertState(boolean expression, String msg, Object...args) throws IllegalStateException { 097 if (! expression) 098 throw illegalState(msg, args); 099 } 100 101 /** 102 * Throws an {@link IllegalArgumentException} if the specified argument is <jk>null</jk>. 103 * 104 * <h5 class='section'>Example:</h5> 105 * <p class='bjava'> 106 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 107 * 108 * <jk>public</jk> String setFoo(String <jv>foo</jv>) { 109 * <jsm>assertArgNotNull</jsm>(<js>"foo"</js>, <jv>foo</jv>); 110 * ... 111 * } 112 * </p> 113 * 114 * @param <T> The argument data type. 115 * @param name The argument name. 116 * @param o The object to check. 117 * @return The same argument. 118 * @throws IllegalArgumentException Constructed exception. 119 */ 120 public static final <T> T assertArgNotNull(String name, T o) throws IllegalArgumentException { 121 assertArg(o != null, "Argument ''{0}'' cannot be null.", name); 122 return o; 123 } 124 125 /** 126 * Asserts that the specified object is not <jk>null</jk>, throwing an {@link IllegalStateException} if it is. 127 * 128 * @param <T> The type of the object. 129 * @param o The object to check. Can be <jk>null</jk>. 130 * @param msg The error message format string. Must not be <jk>null</jk>. 131 * @param args The arguments for the message format string. 132 * @return The non-null object. 133 * @throws IllegalStateException If the object is <jk>null</jk>. 134 */ 135 public static final <T> T assertNotNull(T o, String msg, Object...args) throws IllegalStateException { 136 if (o == null) 137 throw illegalState(msg, args); 138 return o; 139 } 140 141 /** 142 * Throws an {@link IllegalArgumentException} if the specified string is <jk>null</jk> or blank. 143 * 144 * @param name The argument name. 145 * @param o The object to check. 146 * @return The same object. 147 * @throws IllegalArgumentException Thrown if the specified string is <jk>null</jk> or blank. 148 */ 149 public static final String assertArgNotNullOrBlank(String name, String o) throws IllegalArgumentException { 150 assertArgNotNull(name, o); 151 assertArg(! o.isBlank(), "Argument ''{0}'' cannot be blank.", name); 152 return o; 153 } 154 155 /** 156 * Throws an {@link IllegalArgumentException} if any of the specified arguments are <jk>null</jk>. 157 * 158 * <h5 class='section'>Example:</h5> 159 * <p class='bjava'> 160 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 161 * 162 * <jk>public</jk> String setFooBar(String <jv>foo</jv>, String <jv>bar</jv>) { 163 * <jsm>assertArgsNotNull</jsm>(<js>"foo"</js>, <jv>foo</jv>, <js>"bar"</js>, <jv>bar</jv>); 164 * ... 165 * } 166 * </p> 167 * 168 * @param name1 The first argument name. 169 * @param o1 The first object to check. 170 * @param name2 The second argument name. 171 * @param o2 The second object to check. 172 * @throws IllegalArgumentException Constructed exception. 173 */ 174 public static final void assertArgsNotNull(String name1, Object o1, String name2, Object o2) throws IllegalArgumentException { 175 assertArgNotNull(name1, o1); 176 assertArgNotNull(name2, o2); 177 } 178 179 /** 180 * Throws an {@link IllegalArgumentException} if any of the specified arguments are <jk>null</jk>. 181 * 182 * <h5 class='section'>Example:</h5> 183 * <p class='bjava'> 184 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 185 * 186 * <jk>public</jk> String setFooBarBaz(String <jv>foo</jv>, String <jv>bar</jv>, String <jv>baz</jv>) { 187 * <jsm>assertArgsNotNull</jsm>(<js>"foo"</js>, <jv>foo</jv>, <js>"bar"</js>, <jv>bar</jv>, <js>"baz"</js>, <jv>baz</jv>); 188 * ... 189 * } 190 * </p> 191 * 192 * @param name1 The first argument name. 193 * @param o1 The first object to check. 194 * @param name2 The second argument name. 195 * @param o2 The second object to check. 196 * @param name3 The third argument name. 197 * @param o3 The third object to check. 198 * @throws IllegalArgumentException Constructed exception. 199 */ 200 public static final void assertArgsNotNull(String name1, Object o1, String name2, Object o2, String name3, Object o3) throws IllegalArgumentException { 201 assertArgNotNull(name1, o1); 202 assertArgNotNull(name2, o2); 203 assertArgNotNull(name3, o3); 204 } 205 206 /** 207 * Throws an {@link IllegalArgumentException} if any of the specified arguments are <jk>null</jk>. 208 * 209 * @param name1 The first argument name. 210 * @param o1 The first object to check. 211 * @param name2 The second argument name. 212 * @param o2 The second object to check. 213 * @param name3 The third argument name. 214 * @param o3 The third object to check. 215 * @param name4 The fourth argument name. 216 * @param o4 The fourth object to check. 217 * @throws IllegalArgumentException Constructed exception. 218 */ 219 public static final void assertArgsNotNull(String name1, Object o1, String name2, Object o2, String name3, Object o3, String name4, Object o4) throws IllegalArgumentException { 220 assertArgNotNull(name1, o1); 221 assertArgNotNull(name2, o2); 222 assertArgNotNull(name3, o3); 223 assertArgNotNull(name4, o4); 224 } 225 226 /** 227 * Throws an {@link IllegalArgumentException} if any of the specified arguments are <jk>null</jk>. 228 * 229 * @param name1 The first argument name. 230 * @param o1 The first object to check. 231 * @param name2 The second argument name. 232 * @param o2 The second object to check. 233 * @param name3 The third argument name. 234 * @param o3 The third object to check. 235 * @param name4 The fourth argument name. 236 * @param o4 The fourth object to check. 237 * @param name5 The fifth argument name. 238 * @param o5 The fifth object to check. 239 * @throws IllegalArgumentException Constructed exception. 240 */ 241 public static final void assertArgsNotNull(String name1, Object o1, String name2, Object o2, String name3, Object o3, String name4, Object o4, String name5, Object o5) 242 throws IllegalArgumentException { 243 assertArgNotNull(name1, o1); 244 assertArgNotNull(name2, o2); 245 assertArgNotNull(name3, o3); 246 assertArgNotNull(name4, o4); 247 assertArgNotNull(name5, o5); 248 } 249 250 /** 251 * Throws an {@link IllegalArgumentException} if the specified object is not an instance of the specified type. 252 * 253 * <h5 class='section'>Example:</h5> 254 * <p class='bjava'> 255 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 256 * 257 * <jk>public</jk> <jk>void</jk> setValue(Object <jv>value</jv>) { 258 * <jc>// Validate that value is a String</jc> 259 * <jsm>assertType</jsm>(String.<jk>class</jk>, <jv>value</jv>); 260 * ... 261 * } 262 * </p> 263 * 264 * @param <T> The expected type. 265 * @param type The expected class type. 266 * @param o The object to check. 267 * @return The object cast to the specified type. 268 * @throws IllegalArgumentException Thrown if the object is not an instance of the specified type. 269 */ 270 @SuppressWarnings({ "unchecked" }) 271 public static final <T> T assertType(Class<T> type, Object o) throws IllegalArgumentException { 272 assertArgNotNull("type", type); 273 assertArgNotNull("o", o); 274 if (! type.isInstance(o)) 275 throw illegalArg("Object is not an instance of {0}: {1}", cn(type), cn(o)); 276 return (T)o; 277 } 278 279 /** 280 * Throws the exception provided by the supplier if the specified object is not an instance of the specified type. 281 * 282 * <h5 class='section'>Example:</h5> 283 * <p class='bjava'> 284 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 285 * 286 * <jk>public</jk> <jk>void</jk> setValue(Object <jv>value</jv>) { 287 * <jc>// Validate that value is a String, throw custom exception</jc> 288 * <jsm>assertType</jsm>(String.<jk>class</jk>, <jv>value</jv>, () -> <jk>new</jk> IllegalStateException(<js>"Invalid value type"</js>)); 289 * ... 290 * } 291 * </p> 292 * 293 * @param <T> The expected type. 294 * @param type The expected class type. 295 * @param o The object to check. 296 * @param exceptionSupplier The supplier that provides the exception to throw if validation fails. 297 * @return The object cast to the specified type. 298 * @throws RuntimeException Thrown if the object is not an instance of the specified type (the exception is provided by the supplier). 299 */ 300 @SuppressWarnings({ "unchecked" }) 301 public static final <T> T assertType(Class<T> type, Object o, java.util.function.Supplier<? extends RuntimeException> exceptionSupplier) throws RuntimeException { 302 assertArgNotNull("type", type); 303 assertArgNotNull("o", o); 304 if (! type.isInstance(o)) 305 throw exceptionSupplier.get(); 306 return (T)o; 307 } 308 309 /** 310 * Throws an {@link IllegalArgumentException} if the specified value doesn't have all subclasses of the specified type. 311 * 312 * @param <E> The element type. 313 * @param name The argument name. 314 * @param type The expected parent class. 315 * @param value The array value being checked. 316 * @return The value cast to the specified array type. 317 * @throws IllegalArgumentException Constructed exception. 318 */ 319 @SuppressWarnings("unchecked") 320 public static final <E> Class<E>[] assertClassArrayArgIsType(String name, Class<E> type, Class<?>[] value) throws IllegalArgumentException { 321 for (var i = 0; i < value.length; i++) 322 if (! type.isAssignableFrom(value[i])) 323 throw illegalArg("Arg {0} did not have arg of type {1} at index {2}: {3}", name, cn(type), i, cn(value[i])); 324 return (Class<E>[])value; 325 } 326 327 /** 328 * Throws an {@link AssertionError} if the specified actual value is not one of the expected values. 329 * 330 * @param <T> The value type. 331 * @param actual The actual value. 332 * @param expected The expected values. 333 * @return The actual value if it matches one of the expected values. 334 * @throws AssertionError if the value is not one of the expected values. 335 */ 336 @SafeVarargs 337 public static final <T> T assertOneOf(T actual, T...expected) { 338 for (var e : expected) { 339 if (eq(actual, e)) 340 return actual; 341 } 342 throw new AssertionError("Invalid value specified: " + actual); 343 } 344 345 /** 346 * Throws an {@link IllegalArgumentException} if the specified varargs array or any of its elements are <jk>null</jk>. 347 * 348 * @param <T> The element type. 349 * @param name The argument name. 350 * @param o The object to check. 351 * @return The same object. 352 * @throws IllegalArgumentException Thrown if the specified varargs array or any of its elements are <jk>null</jk>. 353 */ 354 public static final <T> T[] assertArgNoNulls(String name, T[] o) throws IllegalArgumentException { 355 assertArgNotNull(name, o); 356 for (var i = 0; i < o.length; i++) 357 assertArg(nn(o[i]), "Argument ''{0}'' parameter {1} cannot be null.", name, i); 358 return o; 359 } 360 361 /** 362 * Throws an {@link IllegalArgumentException} if the specified collection or any of its elements are <jk>null</jk>. 363 * 364 * <h5 class='section'>Example:</h5> 365 * <p class='bjava'> 366 * <jk>import static</jk> org.apache.juneau.commons.utils.AssertionUtils.*; 367 * 368 * <jk>public</jk> <jk>void</jk> setValues(List<String> <jv>values</jv>) { 369 * <jsm>assertCollectionArgNotNull</jsm>(<js>"values"</js>, <jv>values</jv>); 370 * ... 371 * } 372 * </p> 373 * 374 * @param <T> The element type. 375 * @param <C> The collection type. 376 * @param name The argument name. 377 * @param collection The collection to check. 378 * @return The same collection. 379 * @throws IllegalArgumentException Thrown if the specified collection or any of its elements are <jk>null</jk>. 380 */ 381 public static final <T, C extends Collection<T>> C assertArgNoNulls(String name, C collection) throws IllegalArgumentException { 382 assertArgNotNull(name, collection); 383 var i = 0; 384 for (var element : collection) 385 assertArg(nn(element), "Argument ''{0}'' element at index {1} cannot be null.", name, i++); 386 return collection; 387 } 388 389}