001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.lang;
020
021import static java.lang.Integer.signum;
022import static java.util.Arrays.deepToString;
023import static org.apiguardian.api.API.Status.DEPRECATED;
024import static org.apiguardian.api.API.Status.STABLE;
025import static org.tquadrat.foundation.lang.CommonConstants.NULL_STRING;
026
027import java.lang.reflect.Array;
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.Comparator;
032import java.util.Enumeration;
033import java.util.List;
034import java.util.Map;
035import java.util.Optional;
036import java.util.function.BiFunction;
037import java.util.function.DoublePredicate;
038import java.util.function.Function;
039import java.util.function.IntPredicate;
040import java.util.function.LongPredicate;
041import java.util.function.Predicate;
042import java.util.function.Supplier;
043import java.util.function.UnaryOperator;
044
045import org.apiguardian.api.API;
046import org.tquadrat.foundation.annotation.ClassVersion;
047import org.tquadrat.foundation.annotation.UtilityClass;
048import org.tquadrat.foundation.exception.BlankArgumentException;
049import org.tquadrat.foundation.exception.EmptyArgumentException;
050import org.tquadrat.foundation.exception.NullArgumentException;
051import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
052import org.tquadrat.foundation.exception.ValidationException;
053
054/**
055 *  <p>{@summary This class consists of several utility methods working on
056 *  {@link Object}
057 *  instances, similar to those on
058 *  {@link Arrays}
059 *  or
060 *  {@link Collections}.}</p>
061 *  <p>The class was originally inspired by the class of the same name that
062 *  was finally introduced with the Java&nbsp;7 release; some of its methods
063 *  will delegate to
064 *  {@link java.util.Objects java.util.Objects},
065 *  others will extend the functionality of the methods with the same
066 *  name from {@code java.util.Objects}.</p>
067 *  <p>If a method from {@code java.util.Objects} would throw a
068 *  {@link NullPointerException},
069 *  the method with the same name from this class would throw a
070 *  {@link ValidationException}
071 *  instead.</p>
072 *
073 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
074 *  @version $Id: Objects.java 1258 2026-06-04 18:33:06Z tquadrat $
075 *  @since 0.0.1
076 *
077 *  @UMLGraph.link
078 */
079@UtilityClass
080@SuppressWarnings( {"ClassWithTooManyMethods", "UseOfObsoleteDateTimeApi", "OverlyComplexClass"} )
081@ClassVersion( sourceVersion = "$Id: Objects.java 1258 2026-06-04 18:33:06Z tquadrat $" )
082@API( status = STABLE, since = "0.0.1" )
083public final class Objects
084{
085        /*--------------*\
086    ====** Constructors **=====================================================
087        \*--------------*/
088    /**
089     *  No instance allowed for this class.
090     */
091    private Objects() { throw new PrivateConstructorForStaticClassCalledError( Objects.class ); }
092
093        /*---------*\
094    ====** Methods **==========================================================
095        \*---------*/
096    /**
097     *  <p>{@summary Checks if the sub-range from {@code fromIndex} (inclusive)
098     *  to {@code fromIndex + size} (exclusive) is within the bounds of range
099     *  from {@code 0} (inclusive) to {@code length} (exclusive).}</p>
100     *  <p>The sub-range is defined to be out-of-bounds if any of the following
101     *  inequalities is true:</p>
102     *  <ul>
103     *    <li>{@code fromIndex < 0}</li>
104     *    <li>{@code size < 0}</li>
105     *    <li>{@code fromIndex + size > length}, taking into account integer
106     *    overflow</li>
107     *    <li>{@code length < 0}, which is implied from the former
108     *    inequalities</li>
109     *  </ul>
110     *  <p>Calls
111     *  {@link java.util.Objects#checkFromIndexSize(int,int,int) java.util.Objects.checkFromIndexSize(int,int,int)}
112     *  internally.</p>
113     *
114     *  @param  fromIndex   The lower-bound (inclusive) of the sub-interval.
115     *  @param  size    The size of the sub-range.
116     *  @param  length  The upper-bound (exclusive) of the range.
117     *  @return The {@code fromIndex} if the sub-range is within bounds of the
118     *      range.
119     *  @throws IndexOutOfBoundsException   The sub-range is out-of-bounds.
120     *
121     *  @since 0.0.5
122     */
123    @API( status = STABLE, since = "0.0.5" )
124    public static final int checkFromIndexSize( final int fromIndex, final int size, final int length )
125    {
126        final var retValue = java.util.Objects.checkFromIndexSize( fromIndex, size, length );
127
128        //---* Done *----------------------------------------------------------
129        return retValue;
130    }   //  checkFromIndexSize()
131
132    /**
133     *  <p>{@summary Checks if the sub-range from {@code fromIndex} (inclusive)
134     *  to {@code toIndex} (exclusive) is within the bounds of range from
135     *  {@code 0} (inclusive) to {@code length} (exclusive).}</p>
136     *  <p>The sub-range is defined to be out-of-bounds if any of the following
137     *  inequalities is true:</p>
138     *  <ul>
139     *    <li>{@code fromIndex < 0}</li>
140     *    <li>{@code fromIndex > toIndex}</li>
141     *    <li>{@code toIndex > length}</li>
142     *    <li>{@code length < 0}, which is implied from the former
143     *    inequalities</li>
144     *  </ul>
145     *  <p>Calls
146     *  {@link java.util.Objects#checkFromToIndex(int,int,int) java.util.Objects.checkFromToIndex(int,int,int)}
147     *  internally.</p>
148     *
149     *  @param  fromIndex   The lower-bound (inclusive) of the sub-range.
150     *  @param  toIndex The upper-bound (exclusive) of the sub-range.
151     *  @param  length  The upper-bound (exclusive) the range.
152     *  @return The {@code fromIndex} if the sub-range is within bounds of the
153     *      range.
154     *  @throws IndexOutOfBoundsException   The sub-range is out-of-bounds.
155     *
156     *  @since 0.0.5
157     */
158    @API( status = STABLE, since = "0.0.5" )
159    public static final int checkFromToIndex( final int fromIndex, final int toIndex, final int length )
160    {
161        final var retValue = java.util.Objects.checkFromToIndex( fromIndex, toIndex, length );
162
163        //---* Done *----------------------------------------------------------
164        return retValue;
165    }   //  checkFromToIndex()
166
167    /**
168     *  <p>{@summary Checks if the {@code index} is within the bounds of the
169     *  range from {@code 0} (inclusive) to {@code length} (exclusive).}</p>
170     *  <p>The {@code index} is defined to be out-of-bounds if any of the
171     *  following inequalities is true:</p>
172     *  <ul>
173     *    <li>{@code index < 0}</li>
174     *    <li>{@code index >= length}</li>
175     *    <li>{@code length < 0}, which is implied from the former
176     *    inequalities</li>
177     *  </ul>
178     *  <p>Calls
179     *  {@link java.util.Objects#checkIndex(int,int) java.util.Objects.checkIndex(int,int)}
180     *  internally.</p>
181     *
182     *  @param  index   The index.
183     *  @param  length  The upper-bound (exclusive) of the range.
184     *  @return The {@code index} if it is within bounds of the range.
185     *  @throws IndexOutOfBoundsException   The {@code index} is out-of-bounds.
186     *
187     *  @since 0.0.5
188     */
189    @API( status = STABLE, since = "0.0.5" )
190    public static final int checkIndex( final int index, final int length )
191    {
192        final var retValue = java.util.Objects.checkIndex( index, length );
193
194        //---* Done *----------------------------------------------------------
195        return retValue;
196    }   //  checkIndex()
197
198    /**
199     *  <p>{@summary Throws the exception provided by the given supplier if the
200     *  condition resolves to {@false}.}</p>
201     *  <p>Basically, this method is a replacement for the code sequence
202     *  below:</p>
203     *  <div class="source-container"><pre>…
204     *  if( !&lt;<i>condition</i>&gt; )
205     *  {
206     *      throw new &lt;<i>WhatEver</i>&gt;Exception( &lt;<i>WhatEverMessage</i>&gt; );
207     *  }
208     *  …</pre></div>
209     *  <p>Code using this method may be easier to read than the {@code if}
210     *  statement above:</p>
211     *  <div class="source-container"><pre>…
212     *  checkState( &lt;<i>condition</i>&gt;, () -> new &lt;<i>WhatEver</i>&gt;Exception( &lt;<i>WhatEverMessage</i>&gt; ) );
213     *  …</pre></div>
214     *
215     *  @param  <E> The type of the exception that is thrown in case the
216     *      condition is not met.
217     *  @param  condition   The condition to check.
218     *  @param  exception   The exception to throw.
219     *  @throws E   The condition was not met.
220     */
221    @SuppressWarnings( "CheckedExceptionClass" )
222    public static final <E extends Exception> void checkState( final boolean condition, final Supplier<E> exception ) throws E
223    {
224        if( !condition ) throw requireNonNullArgument( exception, "exception" ).get();
225    }   //  checkState()
226
227    /**
228     *  <p>{@summary Returns 0 if the arguments are identical and
229     *  {@code comparator.compare(a, b)} otherwise.}</p>
230     *  <p>Consequently, if both arguments are {@null}, 0 is returned.</p>
231     *  <p>Calls
232     *  {@link java.util.Objects#compare(Object,Object,Comparator) java.util.Objects#compare()}
233     *  internally, but different from that method, this implementation will
234     *  throw a
235     *  {@link NullArgumentException}
236     *  in case the {@code comparator} is {@null}.</p>
237     *
238     *  @param  <T> The type of the objects being compared.
239     *  @param  object  An object.
240     *  @param  other   Another object to be compared with the first object.
241     *  @param  comparator  The
242     *      {@link Comparator}
243     *      to compare the first two arguments.
244     *  @return 0 if the arguments are identical and +1, 0, or -1, based on the
245     *      return value of {@code c.compare(a, b)} otherwise.
246     *  @throws NullArgumentException   The {@code comparator} is {@null}.
247     *
248     *  @see Comparable
249     *  @see Comparator
250     *
251     *  @since 0.0.5
252     */
253    @API( status = STABLE, since = "0.0.5" )
254    public static final <T> int compare( final T object, final T other, final Comparator<? super T> comparator ) throws NullArgumentException
255    {
256        final var retValue = object == other ? 0 : signum( java.util.Objects.compare( object, other, requireNonNullArgument( comparator, "comparator" ) ) );
257
258        //---* Done *----------------------------------------------------------
259        return retValue;
260    }   //  compare()
261
262    /**
263     *  <p>{@summary Returns {@true} if the arguments are deeply equal to
264     *  each other and {@false} otherwise.}</p>
265     *  <p>Two {@null} values are deeply equal. If both arguments are
266     *  arrays, the algorithm in
267     *  {@link Arrays#deepEquals(Object[], Object[]) Arrays.deepEquals()}
268     *  is used to determine equality. Otherwise, equality is determined by
269     *  using the
270     *  {@link Object#equals(Object) equals()}
271     *  method of the first argument.</p>
272     *  <p>Calls
273     *  {@link java.util.Objects#deepEquals(Object,Object) java.util.Objects#deepEquals()}
274     *  internally.</p>
275     *
276     *  @param  object  An object.
277     *  @param  other   Another object to be compared with the first object for
278     *      deep equality.
279     *  @return {@true} if the arguments are deeply equal to each other
280     *      and {@false} otherwise.
281     *
282     *  @see    Arrays#deepEquals(Object[],Object[])
283     *  @see    Objects#equals(Object,Object)
284     *
285     *  @since 0.0.5
286     */
287    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
288    @API( status = STABLE, since = "0.0.5" )
289    public static final boolean deepEquals( final Object object, final Object other ) { return java.util.Objects.deepEquals( object, other ); }
290
291    /**
292     *  <p>{@summary Returns {@true} if the arguments are equal to each
293     *  other and {@false} otherwise.}</p>
294     *  <p> Consequently, if both arguments are {@null}, {@true} is
295     *  returned and if exactly one argument is {@null}, {@false} is
296     *  returned.  Otherwise, equality is determined by using the
297     *  {@link Object#equals(Object) equals()}
298     *  method of the first argument.</p>
299     *  <p>Calls
300     *  {@link java.util.Objects#equals(Object, Object)}
301     *  internally.</p>
302     *
303     *  @param  object  An object.
304     *  @param  other   Another object to be compared with the first one for
305     *      equality.
306     *  @return {@true} if the arguments are equal to each other and
307     *      {@false} otherwise.
308     *
309     *  @see    Object#equals(Object)
310     *
311     *  @since 0.0.5
312     */
313    @API( status = STABLE, since = "0.0.5" )
314    public static final boolean equals( final Object object, final Object other ) { return java.util.Objects.equals( object, other ); }
315
316    /**
317     *  <p>{@summary Generates a hash code for a sequence of input values.} The
318     *  hash code is generated as if all the input values were placed into an
319     *  array, and that array is hashed by calling
320     *  {@link Arrays#hashCode(Object[])}.</p>
321     *  <p>Calls
322     *  {@link java.util.Arrays#hashCode(Object[]) java.util.Arrays.hashCode()}
323     *  internally.</p>
324     *
325     *  @param  values  The values to be hashed.
326     *  @return A hash value of the sequence of input values.
327     *
328     *  @see    List#hashCode
329     *
330     *  @since 0.0.5
331     */
332    @API( status = STABLE, since = "0.0.5" )
333    public static final int hash( final Object... values ) { return Arrays.hashCode( values ); }
334
335    /**
336     *  <p>{@summary Returns the hash code of a non-{@null} argument and 0
337     *  for a {@null} argument.}</p>
338     *  <p>Calls
339     *  {@link java.util.Objects#hashCode(Object) java.util.Objects.hashCode(Object)}
340     *  internally.</p>
341     *
342     *  @param o   An object.
343     *  @return The hash code of an argument that is not {@null}, and 0
344     *      for a {@null} argument,
345     *
346     *  @see    Object#hashCode
347     *
348     *  @since 0.0.5
349     */
350    @API( status = STABLE, since = "0.0.5" )
351    public static final int hashCode( final Object o ) { return java.util.Objects.hashCode( o ); }
352
353    /**
354     *  <p>{@summary Returns {@true} if the provided reference is
355     *  {@null}, otherwise returns {@false}.}</p>
356     *  <p>This method can be used as a
357     *  {@link java.util.function.Predicate},
358     *  {@code filter(Objects::isNull)}.</p>
359     *  <p>Calls
360     *  {@link java.util.Objects#isNull(Object) java.util.Objects.isNull()}
361     *  internally.</p>
362     *
363     *  @param  obj A reference to be checked against {@null}.
364     *  @return {@true} if the provided reference is {@null},
365     *      otherwise {@false}
366     *
367     *  @see    java.util.function.Predicate
368     *  @see    org.tquadrat.foundation.lang.CommonConstants#IS_NULL
369     *
370     *  @since 0.0.5
371     */
372    @API( status = STABLE, since = "0.0.5" )
373    public static final boolean isNull( final Object obj ) { return java.util.Objects.isNull( obj ); }
374
375    /**
376     *  <p>{@summary Provides a replacement value if the given value is
377     *  {@null}.}</p>
378     *  <p>This is basically a shortcut to</p>
379     *  <div class="source-container"><pre>Optional.ofNullable( value ).orElseGet( supplier );</pre></div>
380     *
381     *  @param  <T> The type of the object to map.
382     *  @param  value   The object to map; can be {@null} (obviously).
383     *  @param  supplier    The supplier for the replacement function.
384     *  @return The provided object if that is not {@null}, or the result
385     *      from the supplier method. Keep in mind that this result can be
386     *      {@null}!
387     *
388     *  @see Optional
389     *  @see Optional#orElseGet(Supplier)
390     *
391     *  @since 0.2.2
392     */
393    @API( status = STABLE, since = "0.2.2" )
394    public static final <T> T mapFromNull( final T value, final Supplier<? extends T> supplier )
395    {
396        requireNonNullArgument( supplier, "supplier" );
397        final var retValue = isNull( value )
398            ? supplier.get()
399            : value;
400
401        //---* Done *----------------------------------------------------------
402        return retValue;
403    }   //  mapFromNull()
404
405    /**
406     *  <p>{@summary Provides a replacement value if the given value is
407     *  {@null}.}</p>
408     *  <p>This is basically a shortcut to</p>
409     *  <div class="source-container"><pre>Optional.ofNullable( value ).orElse( replacement );</pre></div>
410     *
411     *  @param  <T> The type of the object to map.
412     *  @param  value   The object to map; can be {@null}.
413     *  @param  replacement  The replacement value; it may not be {@null}.
414     *  @return The provided object if that is not {@null}, or the
415     *      replacement value.
416     *
417     *  @see Optional
418     *  @see Optional#orElse(Object)
419     *
420     *  @since 0.4.2
421     */
422    @API( status = STABLE, since = "0.4.2" )
423    public static final <T> T mapFromNull( final T value, final T replacement )
424    {
425        requireNonNullArgument( replacement, "replacement" );
426        final var retValue = isNull( value )
427                             ? replacement
428                             : value;
429
430        //---* Done *----------------------------------------------------------
431        return retValue;
432    }   //  mapFromNull()
433
434    /**
435     *  <p>{@summary Maps (converts) the given object instance by applying the
436     *  provided mapper if the instance is not {@null}.}</p>
437     *  <p>The mapper function will not be called at all if the given instance
438     *  is {@null}.</p>
439     *
440     *  @param  <T> The type of the object to map.
441     *  @param  <R> The type of the result.
442     *  @param  o   The object to map; can be {@null}.
443     *  @param  mapper  The mapping function.
444     *  @return The result of the mapping, or {@null} if the given object
445     *      instance was already {@null}. Keep in mind that the result of
446     *      the mapping can be {@null}!
447     */
448    public static final <T,R> R mapNonNull( final T o, final Function<T,? extends R> mapper )
449    {
450        @SuppressWarnings( "RedundantExplicitVariableType" )
451        final R retValue = nonNull( o ) ? requireNonNullArgument( mapper, "mapper" ).apply( o ) : null;
452
453        //---* Done *----------------------------------------------------------
454        return retValue;
455    }   //  mapNonNull()
456
457    /**
458     *  <p>{@summary Maps (converts) the given object instance by applying the
459     *  provided mapper if the instance is not {@null} or returns the
460     *  given default value.}</p>
461     *  <p>The mapper function will not be called at all if the given instance
462     *  is {@null}.</p>
463     *
464     *  @param  <T> The type of the object to map.
465     *  @param  <R> The type of the result.
466     *  @param  o   The object to map; can be {@null}.
467     *  @param  mapper  The mapping function.
468     *  @param  defaultValue    The default value; can be {@null}.
469     *  @return The result of the mapping, or the default value if the given
470     *      object instance is {@null}. Keep in mind that the result of
471     *      the mapping can be {@null}!
472     */
473    public static final <T,R> R mapNonNull( final T o, final Function<T,? extends R> mapper, final R defaultValue )
474    {
475        @SuppressWarnings( "RedundantExplicitVariableType" )
476        final R retValue = nonNull( o ) ? requireNonNullArgument( mapper, "mapper" ).apply( o ) : defaultValue;
477
478        //---* Done *----------------------------------------------------------
479        return retValue;
480    }   //  mapNonNull()
481
482    /**
483     *  <p>{@summary Returns {@true} if the provided reference is not
484     *  {@null}, otherwise returns {@false}.}</p>
485     *  <p>This method exists to be used as a
486     *  {@link java.util.function.Predicate},
487     *  {@code filter(Objects::nonNull)}</p>
488     *  <p>Calls
489     *  {@link java.util.Objects#nonNull(Object) java.util.Objects.nonNull()}
490     *  internally.</p>
491     *
492     *  @param  obj A reference to be checked against {@null}
493     *  @return {@false} if the provided reference is {@null},
494     *      otherwise {@true}
495     *
496     *  @see java.util.function.Predicate
497     *  @see org.tquadrat.foundation.lang.CommonConstants#NON_NULL
498     *
499     *  @since 0.0.5
500     */
501    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
502    @API( status = STABLE, since = "0.0.5" )
503    public static final boolean nonNull( final Object obj ) { return java.util.Objects.nonNull( obj ); }
504
505    /**
506     *  Applies the given validation on the given value, and if that fails, an
507     *  {@link ValidationException}
508     *  is thrown.
509     *
510     *  @param  <T> The type of the value to check.
511     *  @param  obj The value to check; can be {@null}.
512     *  @param  validation  The validation
513     *  @return The value if the validation succeeds.
514     *  @throws ValidationException {@code obj} failed the validation.
515     *
516     *  @since 0.1.0
517     */
518    @SuppressWarnings( "NewExceptionWithoutArguments" )
519    @API( status = STABLE, since = "0.1.0" )
520    public static final <T> T require( final T obj, final Predicate<? super T> validation ) throws ValidationException
521    {
522        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
523        {
524            throw new ValidationException();
525        }
526
527        //---* Done *----------------------------------------------------------
528        return obj;
529    }   //  require()
530
531    /**
532     *  Applies the given validation on the given value, and if that fails, an
533     *  {@link ValidationException}
534     *  with the specified message is thrown.
535     *
536     *  @param  <T> The type of the value to check.
537     *  @param  obj The value to check; can be {@null}.
538     *  @param  message The message that is set to the thrown exception.
539     *  @param  validation  The validation
540     *  @return The value if the validation succeeds.
541     *  @throws ValidationException {@code obj} failed the validation.
542     *  @throws NullArgumentException   {@code message} is {@null}.
543     *  @throws EmptyArgumentException  {@code message} is the empty String.
544     *
545     *  @since 0.1.0
546     */
547    @API( status = STABLE, since = "0.1.0" )
548    public static final <T> T require( final T obj, final String message, final Predicate<? super T> validation ) throws ValidationException, NullArgumentException, EmptyArgumentException
549    {
550        requireNotEmptyArgument( message, "message" );
551
552        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
553        {
554            throw new ValidationException( message );
555        }
556
557        //---* Done *----------------------------------------------------------
558        return obj;
559    }   //  require()
560
561    /**
562     *  <p>{@summary Applies the given validation on the given value, and if
563     *  that fails, a customized
564     *  {@link ValidationException}
565     *  is thrown.}</p>
566     *  <p>Unlike the method
567     *  {@link #require(Object,String,Predicate)},
568     *  this method allows to defer the creation of the message until after the
569     *  validation was performed (and failed). While this may confer a
570     *  performance advantage in the success case, some care should be taken
571     *  that the costs for the creation of the message supplier are less than
572     *  the cost of just creating the String message directly.</p>
573     *
574     *  @param  <T> The type of the value to check.
575     *  @param  obj The value to check; can be {@null}.
576     *  @param  messageSupplier The supplier of the detail message to be used
577     *      in the event that {@code ValidationException} is thrown. If
578     *      {@null} or if it returns {@null}, no detail message is
579     *      provided to the exception.
580     *  @param  validation  The validation
581     *  @return The value if the validation succeeds.
582     *  @throws NullArgumentException   The validation is {@null}.
583     *  @throws ValidationException {@code obk} failed the validation.
584     *
585     *  @since 0.1.0
586     */
587    @SuppressWarnings( "NewExceptionWithoutArguments" )
588    @API( status = STABLE, since = "0.1.0" )
589    public static final <T> T require( final T obj, final Supplier<String> messageSupplier, final Predicate<? super T> validation ) throws ValidationException
590    {
591        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
592        {
593            final var exception = nonNull( messageSupplier )
594                ? new ValidationException( messageSupplier.get() )
595                : new ValidationException();
596            throw exception;
597        }
598
599        //---* Done *----------------------------------------------------------
600        return obj;
601    }   //  require()
602
603    /**
604     *  <p>{@summary Applies the given validation on the given value, and if
605     *  that fails, a customized
606     *  {@link ValidationException}
607     *  is thrown.}</p>
608     *  <p>Unlike the method
609     *  {@link #require(Object,String,Predicate)},
610     *  this method allows to defer the creation of the message until after the
611     *  validation was performed (and failed). While this may confer a
612     *  performance advantage in the success case, some care  should be taken
613     *  that the costs the creation of the message supplier are less than the
614     *  cost of just creating the String message directly.</p>
615     *  <p>This implementation is different from
616     *  {@link #requireNonNull(Object, Supplier)}
617     *  as it takes an instance of
618     *  {@link Function}
619     *  for the {@code messageSupplier}. That function is called with
620     *  {@code obj} as the argument; this allows to add the invalid value to
621     *  the exception detail message. The provided message supplier function
622     *  must accept {@null} as a valid argument.</p>
623     *
624     *  @param  <T> The type of the value to check.
625     *  @param  obj The value to check; can be {@null}.
626     *  @param  messageSupplier The supplier of the detail message to be used
627     *      in the event that a {@code ValidationException} is thrown. If
628     *      {@null} or if it returns {@null}, no detail message is
629     *      provided.
630     *  @param  validation  The validation
631     *  @return The value if the validation succeeds.
632     *  @throws NullArgumentException   The validation is {@null}.
633     *  @throws ValidationException {@code obj} failed the validation.
634     *
635     *  @since 0.1.0
636     */
637    @SuppressWarnings( "NewExceptionWithoutArguments" )
638    @API( status = STABLE, since = "0.1.0" )
639    public static final <T> T require( final T obj, final Function<? super T,String> messageSupplier, final Predicate<? super T> validation ) throws ValidationException
640    {
641        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
642        {
643            final var exception = nonNull( messageSupplier )
644                ? new ValidationException( messageSupplier.apply( obj ) )
645                : new NullArgumentException();
646            throw exception;
647        }
648
649        //---* Done *----------------------------------------------------------
650        return obj;
651    }   //  require()
652
653    /**
654     *  <p>{@summary Checks if the given value {@code obj} is {@null} and
655     *  throws a
656     *  {@link NullArgumentException}
657     *  if it is {@null}.}</p>
658     *
659     *  @param  <T> The type of the value to check.
660     *  @param  obj The value to check.
661     *  @return The value if it is not {@null}.
662     *  @throws NullArgumentException   {@code obj} is {@null}.
663     *
664     *  @see java.util.Objects#requireNonNull(Object)
665     *
666     *  @since 0.0.5
667     */
668    @SuppressWarnings( "NewExceptionWithoutArguments" )
669    @API( status = STABLE, since = "0.0.5" )
670    public static final <T> T requireNonNull( final T obj ) throws NullArgumentException
671    {
672        if( isNull( obj ) ) throw new NullArgumentException();
673
674        //---* Done *----------------------------------------------------------
675        return obj;
676    }   //  requireNonNull()
677
678    /**
679     *  <p>{@summary Checks if the given value {@code obj} is {@null} and
680     *  throws a
681     *  {@link ValidationException}
682     *  with the specified message if it is {@null}.}</p>
683     *
684     *  @param  <T> The type of the value to check.
685     *  @param  obj The value to check.
686     *  @param  message The message that is set to the thrown exception.
687     *  @return The value if it is not {@null}.
688     *  @throws NullArgumentException   {@code message} or {@code obj} is
689     *      {@null}.
690     *  @throws EmptyArgumentException  {@code message} is the empty String.
691     *
692     *  @see java.util.Objects#requireNonNull(Object,String)
693     *
694     *  @since 0.0.5
695     */
696    @API( status = STABLE, since = "0.0.5" )
697    public static final <T> T requireNonNull( final T obj, final String message ) throws ValidationException, NullArgumentException, EmptyArgumentException
698    {
699        requireNotEmptyArgument( message, "message" );
700        if( isNull( obj ) ) throw new ValidationException( message );
701
702        //---* Done *----------------------------------------------------------
703        return obj;
704    }   //  requireNonNull()
705
706    /**
707     *  <p>{@summary Checks that the specified object reference is not
708     *  {@null} and throws a customized
709     *  {@link ValidationException}
710     *  if it is.}</p>
711     *  <p>Unlike the method
712     *  {@link #requireNonNull(Object,String)},
713     *  this method allows to defer the creation of the message until after the
714     *  null check failed. While this may confer a performance advantage in the
715     *  non-{@null} case, when deciding to call this method care should be
716     *  taken that the costs of creating the message supplier are less than the
717     *  cost of just creating the String message directly.</p>
718     *
719     *  @param  <T> The type of the value to check.
720     *  @param  obj The value to check.
721     *  @param  messageSupplier The supplier of the detail message to be used
722     *      in the event that a {@code NullArgumentException} is thrown. If
723     *      {@null}, no detail message is provided.
724     *  @return The value if it is not {@null}.
725     *  @throws ValidationException    {@code obj} is {@null}
726     *
727     *  @since 0.0.5
728     */
729    @API( status = STABLE, since = "0.0.5" )
730    public static final <T> T requireNonNull( final T obj, final Supplier<String> messageSupplier) throws ValidationException
731    {
732        if( isNull( obj ) )
733        {
734            final var message = nonNull( messageSupplier ) ? messageSupplier.get() : null;
735            @SuppressWarnings( "NewExceptionWithoutArguments" )
736            final var exception = isNull( message ) ? new NullArgumentException() : new ValidationException( message );
737            throw exception;
738        }
739
740        //---* Done *----------------------------------------------------------
741        return obj;
742    }   //  requireNonNull()
743
744    /**
745     *  Checks if the given argument {@code a} is {@null} and throws a
746     *  {@link NullArgumentException}
747     *  if it is {@null}.
748     *
749     *  @param  <T> The type of the argument to check.
750     *  @param  arg The argument to check.
751     *  @param  name    The name of the argument; this is used for the error
752     *      message.
753     *  @return The argument if it is not {@null}.
754     *  @throws NullArgumentException   {@code arg} is {@null}.
755     *
756     *  @since 0.0.5
757     */
758    @API( status = STABLE, since = "0.0.5" )
759    public static final <T> T requireNonNullArgument( final T arg, final String name )
760    {
761        if( isNull( name ) ) throw new NullArgumentException( "name" );
762        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
763        if( name.isBlank() ) throw new BlankArgumentException( "name" );
764        if( isNull( arg ) ) throw new NullArgumentException( name );
765
766        //---* Done *----------------------------------------------------------
767        return arg;
768    }   //  requireNonNullArgument()
769
770    /**
771     *  <p>{@summary Checks if not both of the given arguments {@code arg} and
772     *  {@code otherArg} are {@null} and throws a
773     *  {@link NullArgumentException}
774     *  if both are {@null}.} Otherwise, it returns {@code arg}.</p>
775     *
776     *  @param  <T> The type of the first argument to check.
777     *  @param  arg The first argument to check; it will be returned in case of
778     *      success, even if {@null}.
779     *  @param  otherArg    The other argument to check.
780     *  @param  name    The name of the first argument; this is used for the
781     *      error message.
782     *  @param  otherName   The name of the other argument; this is used for
783     *      the error message.
784     *  @return The first argument, even that might be {@null}.
785     *  @throws NullArgumentException   Both arguments are {@null}.
786     *
787     *  @since 0.0.7
788     */
789    @API( status = STABLE, since = "0.0.7" )
790    public static final <T> T requireNonNullArgument( final T arg, final Object otherArg, final String name, final String otherName )
791    {
792        if( isNull( name ) ) throw new NullArgumentException( "name" );
793        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
794        if( name.isBlank() ) throw new BlankArgumentException( "name" );
795        if( isNull( otherName ) ) throw new NullArgumentException( "otherName" );
796        if( otherName.isEmpty() ) throw new EmptyArgumentException( "otherName" );
797        if( otherName.isBlank() ) throw new BlankArgumentException( "otherName" );
798        if( isNull( arg ) && isNull( otherArg ) )
799        {
800            throw new NullArgumentException( name, otherName );
801        }
802
803        //---* Done *----------------------------------------------------------
804        return arg;
805    }   //  requireNonNullArgument()
806
807    /**
808     *  <p>{@summary Checks if the given String argument {@code arg} is
809     *  {@null}, empty or blank and throws a
810     *  {@link NullArgumentException}
811     *  if it is {@null}, an
812     *  {@link EmptyArgumentException}
813     *  if it is empty, or a
814     *  {@link BlankArgumentException}
815     *  if it is blank.}</p>
816     *
817     *  @param  <T> The type of the argument to check.
818     *  @param  arg The argument to check; may be {@null}.
819     *  @param  name    The name of the argument; this is used for the error
820     *      message.
821     *  @return The argument if it is not {@null}, empty or blank.
822     *  @throws NullArgumentException   {@code arg} is {@null}.
823     *  @throws EmptyArgumentException   {@code arg} is empty.
824     *  @throws BlankArgumentException   {@code arg} is blank.
825     *
826     *  @see    String#isBlank()
827     *
828     *  @since 0.1.0
829     */
830    @SuppressWarnings( "OverlyComplexMethod" )
831    @API( status = STABLE, since = "0.1.0" )
832    public static final <T extends CharSequence> T requireNotBlankArgument( final T arg, final String name )
833    {
834        if( isNull( name ) ) throw new NullArgumentException( "name" );
835        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
836        if( name.isBlank() ) throw new BlankArgumentException( "name" );
837
838        switch( arg )
839        {
840            case null -> throw new NullArgumentException( name );
841            case final String string ->
842            {
843                if( string.isEmpty() ) throw new EmptyArgumentException( name );
844                if( string.isBlank() ) throw new BlankArgumentException( name );
845            }
846            case final CharSequence charSequence ->
847            {
848                if( charSequence.isEmpty() ) throw new EmptyArgumentException( name );
849                if( charSequence.toString().isBlank() ) throw new BlankArgumentException( name );
850            }
851        }
852
853        //---* Done *----------------------------------------------------------
854        return arg;
855    }   //  requireNotBlankArgument()
856
857    /**
858     *  <p>{@summary Checks if the given argument {@code arg} is {@null} or
859     *  empty and throws a
860     *  {@link NullArgumentException}
861     *  if it is {@null}, or an
862     *  {@link EmptyArgumentException}
863     *  if it is empty.}</p>
864     *  <p>Strings, arrays, instances of
865     *  {@link java.util.Collection} and
866     *  {@link java.util.Map}
867     *  as well as instances of
868     *  {@link java.lang.StringBuilder},
869     *  {@link java.lang.StringBuffer},
870     *  and
871     *  {@link java.lang.CharSequence}
872     *  will be checked on being empty.</p>
873     *  <p>For an instance of
874     *  {@link java.util.Optional},
875     *  the presence of a value is checked in order to determine whether the
876     *  {@link Optional} is empty or not.</p>
877     *  <p>Because the interface
878     *  {@link java.util.Enumeration}
879     *  does not provide an API for the check on emptiness
880     *  ({@link java.util.Enumeration#hasMoreElements() hasMoreElements()}
881     *  will return {@false} after all elements have been taken from
882     *  the {@code Enumeration} instance), the result for arguments of this
883     *  type has to be taken with caution.</p>
884     *  <p>For instances of
885     *  {@link java.util.stream.Stream},
886     *  this method will only check for {@null} (like
887     *  {@link #requireNonNullArgument(Object,String)}.
888     *  This is because any operation on the stream itself would render it
889     *  unusable for later processing.</p>
890     *  <p>In case the argument is of type
891     *  {@link Optional},
892     *  this method behaves different from
893     *  {@link #requireNotEmptyArgument(Optional,String)};
894     *  this one will return the {@code Optional} instance, while the other
895     *  method will return the contents of the {@code Optional}.</p>
896     *  <p>This method will not work properly for instances of
897     *  {@link java.util.StringJoiner}, because its method
898     *  {@link java.util.StringJoiner#length() length()}
899     *  will not return 0 when a prefix, suffix, or an
900     *  &quot;{@linkplain java.util.StringJoiner#setEmptyValue(CharSequence) empty value}&quot;
901     *  was provided.</p>
902     *
903     *  @param  <T> The type of the argument to check.
904     *  @param  arg The argument to check; may be {@null}.
905     *  @param  name    The name of the argument; this is used for the error
906     *      message.
907     *  @return The argument if it is not {@null} or empty.
908     *  @throws NullArgumentException   {@code arg} is {@null}.
909     *  @throws EmptyArgumentException   {@code arg} is empty.
910     *
911     *  @since 0.0.5
912     */
913    @SuppressWarnings( "OverlyComplexMethod" )
914    @API( status = STABLE, since = "0.0.5" )
915    public static final <T> T requireNotEmptyArgument( final T arg, final String name )
916    {
917        if( isNull( name ) ) throw new NullArgumentException( "name" );
918        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
919        if( name.isBlank() ) throw new BlankArgumentException( "name" );
920
921        switch( arg )
922        {
923            /*
924             * When using guarding expressions, the code would not get better
925             * to read and to understand, as the positive cases will be handled
926             * all by the default case.
927             */
928            case null -> throw new NullArgumentException( name );
929            case final CharSequence charSequence ->
930            {
931                if( charSequence.isEmpty() ) throw new EmptyArgumentException( name );
932            }
933            case final Collection<?> collection ->
934            {
935                if( collection.isEmpty() ) throw new EmptyArgumentException( name );
936            }
937            case final Map<?,?> map ->
938            {
939                if( map.isEmpty() ) throw new EmptyArgumentException( name );
940            }
941            case final Enumeration<?> enumeration ->
942            {
943                /*
944                 * The funny thing with an Enumeration is that it could have
945                 * been not empty in the beginning, but it may be empty
946                 * (= having no more elements) now.
947                 * The good thing is that Enumeration.hasMoreElements() will
948                 * not change the state of the Enumeration - at least it should
949                 * not do so.
950                 */
951                if( !enumeration.hasMoreElements() ) throw new EmptyArgumentException( name );
952            }
953            case final Optional<?> optional ->
954            {
955                /*
956                 * This is different from the behaviour of
957                 * requireNotEmptyArgument(Optional,String) as the Optional
958                 * will be returned here.
959                 */
960                if( optional.isEmpty() ) throw new EmptyArgumentException( name );
961            }
962            default ->
963            {
964                if( arg.getClass().isArray() )
965                {
966                    if( Array.getLength( arg ) == 0 ) throw new EmptyArgumentException( name );
967                }
968                else
969                {
970                    /*
971                     * Other data types are not further processed; in
972                     * particular, instances of Stream cannot be checked on
973                     * being empty. This is because any operation on the Stream
974                     * itself will change its state and may make the Stream
975                     * unusable.
976                     */
977                }
978            }
979        }
980
981        //---* Done *----------------------------------------------------------
982        return arg;
983    }   //  requireNotEmptyArgument()
984
985    /**
986     *  <p>{@summary Checks if the given argument {@code optional} of type
987     *  {@link Optional}
988     *  is {@null} or
989     *  {@linkplain Optional#empty() empty}
990     *  and throws a
991     *  {@link NullArgumentException}
992     *  if it is {@null}, or a
993     *  {@link EmptyArgumentException}
994     *  if it is empty.}</p>
995     *  <p>Otherwise it returns the value of the {@code Optional}.</p>
996     *  <p>This is different from the behaviour of
997     *  {@link #requireNotEmptyArgument(Object,String)}
998     *  with an instance of {@code Optional} as the argument to test.</p>
999     *
1000     *  @param  <T> The type of the given {@code Optional} to check.
1001     *  @param  optional    The argument to check; can be {@null}.
1002     *  @param  name    The name of the argument; this is used for the error
1003     *      message.
1004     *  @return The value of the argument if {@code optional} is not
1005     *      {@null}
1006     *      and not
1007     *      {@linkplain Optional#empty() empty}. This could be the empty
1008     *      string!
1009     *  @throws NullArgumentException   {@code optional} is {@null}.
1010     *  @throws EmptyArgumentException   {@code optional} is empty.
1011     *
1012     *  @since 0.0.5
1013     */
1014    @API( status = STABLE, since = "0.0.5" )
1015    public static final <T> T requireNotEmptyArgument( @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) final Optional<T> optional, final String name )
1016    {
1017        if( isNull( name ) ) throw new NullArgumentException( "name" );
1018        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
1019        if( name.isBlank() ) throw new BlankArgumentException( "name" );
1020
1021        //---* Check for null *------------------------------------------------
1022        if( isNull( optional ) ) throw new NullArgumentException( name );
1023        final var retValue = optional.orElseThrow( () -> new EmptyArgumentException( name ) );
1024
1025        //---* Done *----------------------------------------------------------
1026        return retValue;
1027    }   //  requireNotEmptyArgument()
1028
1029    /**
1030     *  <p>{@summary Returns the first argument if it is not {@null},
1031     *  otherwise it returns the non-{@null} second argument.}</p>
1032     *  <p>This implementation behaves different from that in
1033     *  {@link java.util.Objects#requireNonNullElse(Object,Object) java.util.Objects.requireNonNullElse(Object,Object)}
1034     *  as it will always check that the default is not {@null}.</p>
1035     *
1036     *  @param <T>  The type of the references.
1037     *  @param  obj An object reference.
1038     *  @param  defaultObj  Another object reference to be returned if the
1039     *      first argument is {@null}.
1040     *  @return The first argument if it is not {@null}, otherwise the
1041     *      second argument if it is not {@null}.
1042     *  @throws NullArgumentException   The {@code defaultObj} is {@null}.
1043     *
1044     *  @see    java.util.Objects#requireNonNullElse(Object, Object)
1045     *
1046     *  @since 0.0.5
1047     */
1048    @API( status = STABLE, since = "0.0.5" )
1049    public static final <T> T requireNonNullElse( final T obj, final T defaultObj ) throws NullArgumentException
1050    {
1051        return java.util.Objects.requireNonNullElse( obj, requireNonNullArgument( defaultObj, "defaultObj" ) );
1052    }   //  requireNonNullElse()
1053
1054    /**
1055     *  <p>{@summary Returns the first argument if it is not {@null},
1056     *  otherwise it returns the non-{@null} value returned by
1057     *  {@link Supplier#get() supplier.get()}.}</p>
1058     *  <p>This implementation behaves different from that in
1059     *  {@link java.util.Objects#requireNonNullElseGet(Object,Supplier) java.util.Objects.requireNonNullElseGet(Object,Supplier)}
1060     *  as it will always check that the supplier is not {@null}.</p>
1061     *
1062     *  @note   Although the provided {@code Supplier} may not be {@null},
1063     *      it may <i>return</i> {@null}.
1064     *
1065     *  @param <T>  The type of the reference.
1066     *  @param  obj An object reference.
1067     *  @param  supplier    The supplier of a non-{@null} object of type
1068     *      {code T} to return if the first argument is {@null}.
1069     *  @return The first argument if it is not {@null}, otherwise the
1070     *      value returned by a call to {@code supplier.get()} if it is not
1071     *      {@null}.
1072     *  @throws NullArgumentException   The {@code supplier} is {@null}.
1073     *  @throws NullPointerException    {@code obj} is {@null} and the
1074     *      return value of {@code supplier.get()} value is {@null}, too.
1075     *
1076     *  @since 0.0.5
1077     */
1078    @SuppressWarnings( "ProhibitedExceptionDeclared" )
1079    @API( status = STABLE, since = "0.0.5" )
1080    public static final <T> T requireNonNullElseGet( final T obj, final Supplier<? extends T> supplier ) throws NullArgumentException, NullPointerException
1081    {
1082        return java.util.Objects.requireNonNullElseGet( obj, requireNonNullArgument( supplier, "supplier" ) );
1083    }   //  requireNonNullElseGet()
1084
1085    /**
1086     *  <p>{@summary Applies the given validation on the given value, and if
1087     *  that fails, an
1088     *  {@link ValidationException}
1089     *  with a default message is thrown.} The validation is also responsible
1090     *  for the {@null}-check; that means, the method
1091     *  {@link Predicate#test(Object) test()}
1092     *  of the validation may be called with {@null} as the argument.</p>
1093     *
1094     *  @param  <T> The type of the value to check.
1095     *  @param  arg The value to check; can be {@null}.
1096     *  @param  name    The name of the argument; this is used for the error
1097     *      message.
1098     *  @param  validation  The validation
1099     *  @return The value if the validation succeeds.
1100     *  @throws ValidationException {@code arg} failed the validation.
1101     *  @throws NullArgumentException   {@code name} or {@code validation} is
1102     *      {@null}.
1103     *  @throws EmptyArgumentException  {@code name} is the empty String.
1104     *
1105     *  @since 0.1.0
1106     */
1107    @API( status = STABLE, since = "0.1.0" )
1108    public static final <T> T requireValidArgument( final T arg, final String name, final Predicate<? super T> validation )
1109    {
1110        requireNotBlankArgument( name, "name" );
1111
1112        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1113        {
1114            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1115        }
1116
1117        //---* Done *----------------------------------------------------------
1118        return arg;
1119    }   //  requireValidArgument()
1120
1121    /**
1122     *  <p>{@summary Applies the given validation on the given value, and if
1123     *  that fails, a
1124     *  {@link ValidationException}
1125     *  is thrown.} The message for the exception will be provided by the given
1126     *  message supplier that takes the name of the argument as an
1127     *  argument.</p>
1128     *  <p>The validation is also responsible for the {@null}-check; that
1129     *  means, the method
1130     *  {@link Predicate#test(Object) test()}
1131     *  of the validation may be called with {@null} as the argument.</p>
1132     *
1133     *  @param  <T> The type of the value to check.
1134     *  @param  arg The value to check; can be {@null}.
1135     *  @param  name    The name of the argument; this is used for the error
1136     *      message.
1137     *  @param  validation  The validation
1138     *  @param  messageSupplier The function that generates the message for the
1139     *      exception.
1140     *  @return The value if the validation succeeds.
1141     *  @throws ValidationException {@code arg} failed the validation.
1142     *  @throws NullArgumentException   {@code name}, {@code validation} or
1143     *      {@code messageProvider} is {@null}.
1144     *  @throws EmptyArgumentException  {@code name} is the empty String.
1145     *
1146     *  @since 0.1.0
1147     *  @deprecated Consider to migrate to
1148     *      {@link #requireValidArgument(Object,String,Predicate,BiFunction)}.
1149     */
1150    @Deprecated( since = "0.25.11", forRemoval = true )
1151    @API( status = DEPRECATED, since = "0.1.0" )
1152    public static final <T> T requireValidArgument( final T arg, final String name, final Predicate<? super T> validation, final UnaryOperator<String> messageSupplier )
1153    {
1154        requireNotBlankArgument( name, "name" );
1155        requireNonNullArgument( messageSupplier, "messageSupplier" );
1156
1157        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1158        {
1159            throw new ValidationException( messageSupplier.apply( name ) );
1160        }
1161
1162        //---* Done *----------------------------------------------------------
1163        return arg;
1164    }   //  requireValidArgument()
1165
1166    /**
1167     *  <p>{@summary Applies the given validation on the given value, and if
1168     *  that fails, a
1169     *  {@link ValidationException}
1170     *  is thrown.} The message for the exception will be provided by the given
1171     *  {@code messageSupplier} that takes the {@code name} as the first
1172     *  argument and the value ({@code arg}) as the second argument to compose
1173     *  the message for the {@code ValidationException} in case the validation
1174     *  failed.</p>
1175     *  <p>The validation is also responsible for the {@null}-check; that
1176     *  means, the method
1177     *  {@link Predicate#test(Object) test()}
1178     *  of the validation may be called with {@null} as the argument.</p>
1179     *
1180     *  @param  <T> The type of the value to check.
1181     *  @param  arg The value to check; can be {@null}.
1182     *  @param  name    The name of the argument; this is used for the error
1183     *      message.
1184     *  @param  validation  The validation
1185     *  @param  messageSupplier The function that generates the message for the
1186     *      exception.
1187     *  @return The value if the validation succeeds.
1188     *  @throws ValidationException {@code arg} failed the validation.
1189     *  @throws NullArgumentException   {@code name}, {@code validation} or
1190     *      {@code messageProvider} is {@null}.
1191     *  @throws EmptyArgumentException  {@code name} is the empty String.
1192     *
1193     *  @since 0.25.11
1194     */
1195    @API( status = STABLE, since = "0.25.11" )
1196    public static final <T> T requireValidArgument( final T arg, final String name, final Predicate<? super T> validation, final BiFunction<String,T,String> messageSupplier )
1197    {
1198        requireNotBlankArgument( name, "name" );
1199        requireNonNullArgument( messageSupplier, "messageSupplier" );
1200
1201        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1202        {
1203            throw new ValidationException( messageSupplier.apply( name, arg ) );
1204        }
1205
1206        //---* Done *----------------------------------------------------------
1207        return arg;
1208    }   //  requireValidArgument()
1209
1210    /**
1211     *  Applies the given validation on the given value, and if that fails, an
1212     *  {@link ValidationException}
1213     *  with a default message is thrown.
1214     *
1215     *  @param  arg The value to check.
1216     *  @param  name    The name of the argument; this is used for the error
1217     *      message.
1218     *  @param  validation  The validation
1219     *  @return The value if the validation succeeds.
1220     *  @throws ValidationException {@code arg} failed the validation.
1221     *  @throws NullArgumentException   {@code name} or {@code validation} is
1222     *      {@null}.
1223     *  @throws EmptyArgumentException  {@code name} is the empty String.
1224     *
1225     *  @since 0.2.0
1226     */
1227    @API( status = STABLE, since = "0.2.0" )
1228    public static final double requireValidDoubleArgument( final double arg, final String name, final DoublePredicate validation )
1229    {
1230        requireNotBlankArgument( name, "name" );
1231
1232        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1233        {
1234            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1235        }
1236
1237        //---* Done *----------------------------------------------------------
1238        return arg;
1239    }   //  requireValidDoubleArgument()
1240
1241    /**
1242     *  <p>{@summary Applies the given validation on the given value, and if
1243     *  that fails, a
1244     *  {@link ValidationException}
1245     *  is thrown.} The message for the exception will be provided by the given
1246     *  message supplier that takes the name of the argument as an
1247     *  argument.</p>
1248     *
1249     *  @param  arg The value to check.
1250     *  @param  name    The name of the argument; this is used for the error
1251     *      message.
1252     *  @param  validation  The validation
1253     *  @param  messageSupplier The function that generates the message for the
1254     *      exception.
1255     *  @return The value if the validation succeeds.
1256     *  @throws ValidationException {@code arg} failed the validation.
1257     *  @throws NullArgumentException   {@code name}, {@code validation} or
1258     *      {@code messageProvider} is {@null}.
1259     *  @throws EmptyArgumentException  {@code name} is the empty String.
1260     *
1261     *  @since 0.2.0
1262     *  @deprecated Consider to migrate to
1263     *      {@link #requireValidDoubleArgument(double,String,DoublePredicate,BiFunction)}
1264     */
1265    @API( status = DEPRECATED, since = "0.2.0" )
1266    @Deprecated( since = "0.25.11", forRemoval = true )
1267    public static final double requireValidDoubleArgument( final double arg, final String name, final DoublePredicate validation, final UnaryOperator<String> messageSupplier )
1268    {
1269        requireNotBlankArgument( name, "name" );
1270        requireNonNullArgument( messageSupplier, "messageSupplier" );
1271
1272        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1273        {
1274            throw new ValidationException( messageSupplier.apply( name ) );
1275        }
1276
1277        //---* Done *----------------------------------------------------------
1278        return arg;
1279    }   //  requireValidDoubleArgument()
1280
1281    /**
1282     *  <p>{@summary Applies the given validation on the given value, and if
1283     *  that fails, a
1284     *  {@link ValidationException}
1285     *  is thrown.} The message for the exception will be provided by the given
1286     *  {@code messageSupplier} that takes the {@code name} as the first
1287     *  argument and the value ({@code arg}) as the second argument to compose
1288     *  the message for the {@code ValidationException} in case the validation
1289     *  failed.</p>
1290     *
1291     *  @param  arg The value to check.
1292     *  @param  name    The name of the argument; this is used for the error
1293     *      message.
1294     *  @param  validation  The validation
1295     *  @param  messageSupplier The function that generates the message for the
1296     *      exception.
1297     *  @return The value if the validation succeeds.
1298     *  @throws ValidationException {@code arg} failed the validation.
1299     *  @throws NullArgumentException   {@code name}, {@code validation} or
1300     *      {@code messageProvider} is {@null}.
1301     *  @throws EmptyArgumentException  {@code name} is the empty String.
1302     *
1303     *  @since 0.25.11
1304     */
1305    @API( status = STABLE, since = "0.25.11" )
1306    public static final double requireValidDoubleArgument( final double arg, final String name, final DoublePredicate validation, final BiFunction<String,Double,String> messageSupplier )
1307    {
1308        requireNotBlankArgument( name, "name" );
1309        requireNonNullArgument( messageSupplier, "messageSupplier" );
1310
1311        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1312        {
1313            throw new ValidationException( messageSupplier.apply( name, Double.valueOf( arg ) ) );
1314        }
1315
1316        //---* Done *----------------------------------------------------------
1317        return arg;
1318    }   //  requireValidDoubleArgument()
1319
1320    /**
1321     *  Applies the given validation on the given value, and if that fails, an
1322     *  {@link ValidationException}
1323     *  with a default message is thrown.
1324     *
1325     *  @param  arg The value to check.
1326     *  @param  name    The name of the argument; this is used for the error
1327     *      message.
1328     *  @param  validation  The validation
1329     *  @return The value if the validation succeeds.
1330     *  @throws ValidationException {@code arg} failed the validation.
1331     *  @throws NullArgumentException   {@code name} or {@code validation} is
1332     *      {@null}.
1333     *  @throws EmptyArgumentException  {@code name} is the empty String.
1334     *
1335     *  @since 0.2.0
1336     */
1337    @API( status = STABLE, since = "0.2.0" )
1338    public static final int requireValidIntegerArgument( final int arg, final String name, final IntPredicate validation )
1339    {
1340        requireNotBlankArgument( name, "name" );
1341
1342        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1343        {
1344            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1345        }
1346
1347        //---* Done *----------------------------------------------------------
1348        return arg;
1349    }   //  requireValidIntegerArgument()
1350
1351    /**
1352     *  <p>{@summary Applies the given validation on the given value, and if
1353     *  that fails, a
1354     *  {@link ValidationException}
1355     *  is thrown.} The message for the exception will be provided by the given
1356     *  message supplier that takes the name of the argument as an
1357     *  argument.</p>
1358     *
1359     *  @param  arg The value to check.
1360     *  @param  name    The name of the argument; this is used for the error
1361     *      message.
1362     *  @param  validation  The validation
1363     *  @param  messageSupplier The function that generates the message for the
1364     *      exception.
1365     *  @return The value if the validation succeeds.
1366     *  @throws ValidationException {@code arg} failed the validation.
1367     *  @throws NullArgumentException   {@code name}, {@code validation} or
1368     *      {@code messageProvider} is {@null}.
1369     *  @throws EmptyArgumentException  {@code name} is the empty String.
1370     *
1371     *  @since 0.2.0
1372     *  @deprecated Consider the migration to
1373     *      {@link #requireValidIntegerArgument(int,String,IntPredicate,BiFunction)}
1374     */
1375    @API( status = DEPRECATED, since = "0.2.0" )
1376    @Deprecated( since = "0.25.11", forRemoval = true )
1377    public static final int requireValidIntegerArgument( final int arg, final String name, final IntPredicate validation, final UnaryOperator<String> messageSupplier )
1378    {
1379        requireNotBlankArgument( name, "name" );
1380        requireNonNullArgument( messageSupplier, "messageSupplier" );
1381
1382        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1383        {
1384            throw new ValidationException( messageSupplier.apply( name ) );
1385        }
1386
1387        //---* Done *----------------------------------------------------------
1388        return arg;
1389    }   //  requireValidIntegerArgument()
1390
1391    /**
1392     *  <p>{@summary Applies the given validation on the given value, and if
1393     *  that fails, a
1394     *  {@link ValidationException}
1395     *  is thrown.} The message for the exception will be provided by the given
1396     *  {@code messageSupplier} that takes the {@code name} as the first
1397     *  argument and the value ({@code arg}) as the second argument to compose
1398     *  the message for the {@code ValidationException} in case the validation
1399     *  failed.</p>
1400     *
1401     *  @param  arg The value to check.
1402     *  @param  name    The name of the argument; this is used for the error
1403     *      message.
1404     *  @param  validation  The validation
1405     *  @param  messageSupplier The function that generates the message for the
1406     *      exception.
1407     *  @return The value if the validation succeeds.
1408     *  @throws ValidationException {@code arg} failed the validation.
1409     *  @throws NullArgumentException   {@code name}, {@code validation} or
1410     *      {@code messageProvider} is {@null}.
1411     *  @throws EmptyArgumentException  {@code name} is the empty String.
1412     *
1413     *  @since 0.25.11
1414     */
1415    @API( status = STABLE, since = "0.25.11" )
1416    public static final int requireValidIntegerArgument( final int arg, final String name, final IntPredicate validation, final BiFunction<String,Integer,String> messageSupplier )
1417    {
1418        requireNotBlankArgument( name, "name" );
1419        requireNonNullArgument( messageSupplier, "messageSupplier" );
1420
1421        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1422        {
1423            throw new ValidationException( messageSupplier.apply( name, Integer.valueOf( arg ) ) );
1424        }
1425
1426        //---* Done *----------------------------------------------------------
1427        return arg;
1428    }   //  requireValidIntegerArgument()
1429
1430    /**
1431     *  Applies the given validation on the given value, and if that fails, an
1432     *  {@link ValidationException}
1433     *  with a default message is thrown.
1434     *
1435     *  @param  arg The value to check.
1436     *  @param  name    The name of the argument; this is used for the error
1437     *      message.
1438     *  @param  validation  The validation
1439     *  @return The value if the validation succeeds.
1440     *  @throws ValidationException {@code arg} failed the validation.
1441     *  @throws NullArgumentException   {@code name} or {@code validation} is
1442     *      {@null}.
1443     *  @throws EmptyArgumentException  {@code name} is the empty String.
1444     *
1445     *  @since 0.2.0
1446     */
1447    @API( status = STABLE, since = "0.2.0" )
1448    public static final long requireValidLongArgument( final long arg, final String name, final LongPredicate validation )
1449    {
1450        requireNotBlankArgument( name, "name" );
1451
1452        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1453        {
1454            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1455        }
1456
1457        //---* Done *----------------------------------------------------------
1458        return arg;
1459    }   //  requireValidLongArgument()
1460
1461    /**
1462     *  <p>{@summary Applies the given validation on the given value, and if
1463     *  that fails, a
1464     *  {@link ValidationException}
1465     *  is thrown.} The message for the exception will be provided by the given
1466     *  message supplier that takes the name of the argument as an
1467     *  argument.</p>
1468     *
1469     *  @param  arg The value to check.
1470     *  @param  name    The name of the argument; this is used for the error
1471     *      message.
1472     *  @param  validation  The validation
1473     *  @param  messageSupplier The function that generates the message for the
1474     *      exception.
1475     *  @return The value if the validation succeeds.
1476     *  @throws ValidationException {@code arg} failed the validation.
1477     *  @throws NullArgumentException   {@code name}, {@code validation} or
1478     *      {@code messageProvider} is {@null}.
1479     *  @throws EmptyArgumentException  {@code name} is the empty String.
1480     *
1481     *  @since 0.2.0
1482     *  @deprecated Consider the migration to
1483     *      {@link #requireValidLongArgument(long,String,LongPredicate,BiFunction)}.
1484     */
1485    @API( status = DEPRECATED, since = "0.2.0" )
1486    @Deprecated( since = "0.25.11" )
1487    public static final long requireValidLongArgument( final long arg, final String name, final LongPredicate validation, final UnaryOperator<String> messageSupplier )
1488    {
1489        requireNotBlankArgument( name, "name" );
1490        requireNonNullArgument( messageSupplier, "messageSupplier" );
1491
1492        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1493        {
1494            throw new ValidationException( messageSupplier.apply( name ) );
1495        }
1496
1497        //---* Done *----------------------------------------------------------
1498        return arg;
1499    }   //  requireValidLongArgument()
1500
1501    /**
1502     *  <p>{@summary Applies the given validation on the given value, and if
1503     *  that fails, a
1504     *  {@link ValidationException}
1505     *  is thrown.} The message for the exception will be provided by the given
1506     *  {@code messageSupplier} that takes the {@code name} as the first
1507     *  argument and the value ({@code arg}) as the second argument to compose
1508     *  the message for the {@code ValidationException} in case the validation
1509     *  failed.</p>
1510     *
1511     *  @param  arg The value to check.
1512     *  @param  name    The name of the argument; this is used for the error
1513     *      message.
1514     *  @param  validation  The validation
1515     *  @param  messageSupplier The function that generates the message for the
1516     *      exception.
1517     *  @return The value if the validation succeeds.
1518     *  @throws ValidationException {@code arg} failed the validation.
1519     *  @throws NullArgumentException   {@code name}, {@code validation} or
1520     *      {@code messageProvider} is {@null}.
1521     *  @throws EmptyArgumentException  {@code name} is the empty String.
1522     *
1523     *  @since 0.25.11
1524     */
1525    @API( status = STABLE, since = "0.25.11" )
1526    public static final long requireValidLongArgument( final long arg, final String name, final LongPredicate validation, final BiFunction<String,Long,String> messageSupplier )
1527    {
1528        requireNotBlankArgument( name, "name" );
1529        requireNonNullArgument( messageSupplier, "messageSupplier" );
1530
1531        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1532        {
1533            throw new ValidationException( messageSupplier.apply( name, Long.valueOf( arg ) ) );
1534        }
1535
1536        //---* Done *----------------------------------------------------------
1537        return arg;
1538    }   //  requireValidLongArgument()
1539
1540    /**
1541     *  <p>{@summary Applies the given validation on the given value (that must
1542     *  not be {@null}), and if that fails, an
1543     *  {@link ValidationException}
1544     *  with a default message is thrown.}</p>
1545     *  <p>If the value is {@null}, the validation is never triggered.</p>
1546     *
1547     *  @param  <T> The type of the value to check.
1548     *  @param  arg The value to check.
1549     *  @param  name    The name of the argument; this is used for the error
1550     *      message.
1551     *  @param  validation  The validation
1552     *  @return The value if the validation succeeds.
1553     *  @throws ValidationException {@code a} failed the validation.
1554     *  @throws NullArgumentException   {@code arg}, {@code name} or
1555     *      {@code validation} is {@null}.
1556     *  @throws EmptyArgumentException  {@code name} is the empty String.
1557     *
1558     *  @since 0.1.0
1559     */
1560    @API( status = STABLE, since = "0.1.0" )
1561    public static final <T> T requireValidNonNullArgument( final T arg, final String name, final Predicate<? super T> validation )
1562    {
1563        requireNotBlankArgument( name, "name" );
1564
1565        if( !requireNonNullArgument( validation, "validation" ).test( requireNonNullArgument( arg, "name" ) ) )
1566        {
1567            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1568        }
1569
1570        //---* Done *----------------------------------------------------------
1571        return arg;
1572    }   //  requireValidNonNullArgument()
1573
1574    /**
1575     *  <p>{@summary Applies the given validation on the given value (that must
1576     *  not be {@null}), and if that fails, a
1577     *  {@link ValidationException}
1578     *  is thrown.} The message for the exception will be provided by the given
1579     *  message supplier that takes the name of the argument as an
1580     *  argument.</p>
1581     *
1582     *  @param  <T> The type of the value to check.
1583     *  @param  arg The value to check.
1584     *  @param  name    The name of the argument; this is used for the error
1585     *      message.
1586     *  @param  validation  The validation
1587     *  @param  messageSupplier The function that generates the message for the
1588     *      exception.
1589     *  @return The value if the validation succeeds.
1590     *  @throws ValidationException {@code arg} failed the validation.
1591     *  @throws NullArgumentException   {@code arg}, {@code name},
1592     *      {@code validation} or {@code messageProvider} is {@null}.
1593     *  @throws EmptyArgumentException  {@code name} is the empty String.
1594     *
1595     *  @since 0.1.0
1596     *  @deprecated Consider the migration to
1597     *      {@link #requireValidNonNullArgument(Object,String,Predicate,BiFunction)}
1598     */
1599    @API( status = DEPRECATED, since = "0.1.0" )
1600    @Deprecated( since = "0.25.11", forRemoval = true )
1601    public static final <T> T requireValidNonNullArgument( final T arg, final String name, final Predicate<? super T> validation, final UnaryOperator<String> messageSupplier )
1602    {
1603        requireNotBlankArgument( name, "name" );
1604        requireNonNullArgument( messageSupplier, "messageSupplier" );
1605
1606        if( !requireNonNullArgument( validation, "validation" ).test( requireNonNullArgument( arg, "name" ) ) )
1607        {
1608            throw new ValidationException( messageSupplier.apply( name ) );
1609        }
1610
1611        //---* Done *----------------------------------------------------------
1612        return arg;
1613    }   //  requireValidNonNullArgument()
1614
1615    /**
1616     *  <p>{@summary Applies the given validation on the given value (that must
1617     *  not be {@null}), and if that fails, a
1618     *  {@link ValidationException}
1619     *  is thrown.} The message for the exception will be provided by the given
1620     *  {@code messageSupplier} that takes the {@code name} as the first
1621     *  argument and the value ({@code arg}) as the second argument to compose
1622     *  the message for the {@code ValidationException} in case the validation
1623     *  failed.</p>
1624     *
1625     *  @param  <T> The type of the value to check.
1626     *  @param  arg The value to check.
1627     *  @param  name    The name of the argument; this is used for the error
1628     *      message.
1629     *  @param  validation  The validation
1630     *  @param  messageSupplier The function that generates the message for the
1631     *      exception.
1632     *  @return The value if the validation succeeds.
1633     *  @throws ValidationException {@code arg} failed the validation.
1634     *  @throws NullArgumentException   {@code arg}, {@code name},
1635     *      {@code validation} or {@code messageProvider} is {@null}.
1636     *  @throws EmptyArgumentException  {@code name} is the empty String.
1637     *
1638     *  @since 0.25.11
1639     */
1640    @API( status = STABLE, since = "0.25.11" )
1641    public static final <T> T requireValidNonNullArgument( final T arg, final String name, final Predicate<? super T> validation, final BiFunction<String,T,String> messageSupplier )
1642    {
1643        requireNotBlankArgument( name, "name" );
1644        requireNonNullArgument( messageSupplier, "messageSupplier" );
1645
1646        if( !requireNonNullArgument( validation, "validation" ).test( requireNonNullArgument( arg, "name" ) ) )
1647        {
1648            throw new ValidationException( messageSupplier.apply( name, arg ) );
1649        }
1650
1651        //---* Done *----------------------------------------------------------
1652        return arg;
1653    }   //  requireValidNonNullArgument()
1654
1655    /**
1656     *  <p>{@summary Converts the given argument {@code object} into a
1657     *  {@link String},
1658     *  usually by calling its
1659     *  {@link Object#toString() toString()}
1660     *  method.} If the value of the argument is {@null}, the text
1661     *  &quot;{@link org.tquadrat.foundation.lang.CommonConstants#NULL_STRING null}&quot;
1662     *  will be returned instead. Arrays will be converted to a String through
1663     *  calling the respective {@code toString()} method from
1664     *  {@link java.util.Arrays}
1665     *  (this distinguishes this implementation from
1666     *  {link java.util.Objects#toString(Object, String) java.util.Objects.toString()}).
1667     *  Values of type
1668     *  {@link java.util.Date} or
1669     *  {@link java.util.Calendar}
1670     *  will be translated based on the default locale - whatever that is.
1671     *
1672     *  @param  object  The object; may be {@null}.
1673     *  @return The object's string representation.
1674     *
1675     *  @see java.util.Arrays#toString(boolean[])
1676     *  @see java.util.Arrays#toString(byte[])
1677     *  @see java.util.Arrays#toString(char[])
1678     *  @see java.util.Arrays#toString(double[])
1679     *  @see java.util.Arrays#toString(float[])
1680     *  @see java.util.Arrays#toString(int[])
1681     *  @see java.util.Arrays#toString(long[])
1682     *  @see java.util.Arrays#toString(Object[])
1683     *  @see java.util.Arrays#toString(short[])
1684     *  @see java.util.Arrays#deepToString(Object[])
1685     *  @see java.util.Locale#getDefault()
1686     *  @see org.tquadrat.foundation.lang.CommonConstants#NULL_STRING
1687     *
1688     *  @since 0.0.5
1689     */
1690    @API( status = STABLE, since = "0.0.5" )
1691    public static final String toString( final Object object )
1692    {
1693        return toString( object, NULL_STRING );
1694    }   //  toString()
1695
1696    /**
1697     *  <p>{@summary Converts the given argument {@code object} into a
1698     *  {@link String},
1699     *  usually by calling its
1700     *  {@link Object#toString() toString()}
1701     *  method.} If the value of the argument is {@null}, the text
1702     *  provided as the {@code nullDefault} argument will be returned
1703     *  instead.</p>
1704     *  <p>Arrays will be converted to a string through calling the respective
1705     *  {@code toString()} method from
1706     *  {@link java.util.Arrays}
1707     *  (this distinguishes this implementation from
1708     *  {link java.util.Objects#toString(Object,String) java.util.Objects.toString(Object,String)}).</p>
1709     *  <p>Values of type
1710     *  {@link java.util.Date} or
1711     *  {@link java.util.Calendar}
1712     *  will be translated based on the
1713     *  {@link java.util.Locale#getDefault() default locale}
1714     *  – whatever that is.</p>
1715     *
1716     *  @param  object  The object; may be {@null}.
1717     *  @param  nullDefault The text that should be returned if {@code object}
1718     *      is {@null}.
1719     *  @return The object's string representation.
1720     *
1721     *  @see java.util.Arrays#toString(boolean[])
1722     *  @see java.util.Arrays#toString(byte[])
1723     *  @see java.util.Arrays#toString(char[])
1724     *  @see java.util.Arrays#toString(double[])
1725     *  @see java.util.Arrays#toString(float[])
1726     *  @see java.util.Arrays#toString(int[])
1727     *  @see java.util.Arrays#toString(long[])
1728     *  @see java.util.Arrays#toString(Object[])
1729     *  @see java.util.Arrays#toString(short[])
1730     *  @see java.util.Arrays#deepToString(Object[])
1731     *  @see java.util.Locale#getDefault()
1732     *
1733     *  @since 0.0.5
1734     */
1735    @SuppressWarnings( {"IfStatementWithTooManyBranches", "ChainOfInstanceofChecks", "OverlyComplexMethod"} )
1736    @API( status = STABLE, since = "0.0.5" )
1737    public static final String toString( final Object object, final String nullDefault )
1738    {
1739        var retValue = requireNonNullArgument( nullDefault, "nullDefault" );
1740        if( nonNull( object ) )
1741        {
1742            final var objectClass = object.getClass();
1743            if( objectClass.isArray() )
1744            {
1745                if( objectClass == byte [].class )
1746                {
1747                    retValue = Arrays.toString( (byte []) object );
1748                }
1749                else if( objectClass == short [].class )
1750                {
1751                    retValue = Arrays.toString( (short []) object );
1752                }
1753                else if( objectClass == int [].class )
1754                {
1755                    retValue = Arrays.toString( (int []) object );
1756                }
1757                else if( objectClass == long [].class )
1758                {
1759                    retValue = Arrays.toString( (long []) object );
1760                }
1761                else if( objectClass == char [].class )
1762                {
1763                    retValue = Arrays.toString( (char []) object );
1764                }
1765                else if( objectClass == float [].class )
1766                {
1767                    retValue = Arrays.toString( (float []) object );
1768                }
1769                else if( objectClass == double [].class )
1770                {
1771                    retValue = Arrays.toString( (double []) object );
1772                }
1773                else if( objectClass == boolean [].class )
1774                {
1775                    retValue = Arrays.toString( (boolean []) object );
1776                }
1777                else
1778                {
1779                    retValue = deepToString( (Object []) object );
1780                }
1781            }
1782            else
1783            {
1784                retValue = object.toString();
1785            }
1786        }
1787
1788        //---* Done *----------------------------------------------------------
1789        return retValue;
1790    }   //  toString()
1791
1792    /**
1793     *  <p>{@summary Converts the given argument into a
1794     *  {@link String}
1795     *  using the given instance of
1796     *  {@link Stringer}.}
1797     *  If the value of the argument is {@null}, the text
1798     *  provided as the {@code nullDefault} argument will be returned
1799     *  instead.</p>
1800     *
1801     *  @param  <T> The type of the object.
1802     *  @param  value   The object; may be {@null}.
1803     *  @param  stringer    The method that is used to convert the given object
1804     *      to a String.
1805     *  @param  nullDefault The text that should be returned if {@code object}
1806     *      is {@null}.
1807     *  @return The object's string representation.
1808     *
1809     *  @see    Stringer
1810     *
1811     *  @since 0.0.5
1812     */
1813    @API( status = STABLE, since = "0.0.5" )
1814    public static final <T> String toString( final T value, final Stringer<? super T> stringer, final String nullDefault )
1815    {
1816        requireNonNullArgument( nullDefault, "nullDefault" );
1817
1818        final var retValue = nonNull( value ) ? requireNonNullArgument( stringer, "stringer" ).toString( value ) : nullDefault;
1819
1820        //---* Done *----------------------------------------------------------
1821        return retValue;
1822    }   //  toString()
1823}
1824//  class Objects
1825
1826/*
1827 *  End of File
1828 */