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