001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 * Licensed to the public under the agreements of the GNU Lesser General Public
007 * License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *      http://www.gnu.org/licenses/lgpl.html
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017
018package org.tquadrat.foundation.exception;
019
020import static java.lang.String.format;
021import static org.apiguardian.api.API.Status.STABLE;
022import static org.tquadrat.foundation.lang.Objects.nonNull;
023import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
024
025import java.io.Serial;
026
027import org.apiguardian.api.API;
028import org.tquadrat.foundation.annotation.ClassVersion;
029
030/**
031 *  <p>{@summary This implementation of
032 *  {@link Error}
033 *  should be thrown in all cases where an <i>unlikely</i> exception was
034 *  caught.}
035 *  Different from an
036 *  {@link ImpossibleExceptionError},
037 *  the exception is <i>possible</i>, but <i>unlikely</i> – probably because
038 *  the programmer has taken (at least thought to have &hellip;) appropriate
039 *  precautions against its occurrence. An example for this could be an
040 *  implementation of
041 *  {@link Object#clone() clone()}
042 *  for a particular class: with implementing that method (and declaring the
043 *  interface
044 *  {@link Cloneable}
045 *  &hellip;), instances of that class do support cloning and therefore that
046 *  exception should not be thrown. Unfortunately, changes somewhere else in
047 *  the source might prevent one of the attributes of the respective class from
048 *  being cloned, so that exception could be thrown again &hellip;</p>
049 *  <p>Another example could be this code sequence:
050 *  <div class="source-container"><pre>…
051 *  final var file = new File( … );
052 *  if( file.exists() )
053 *  {
054 *      try( final var inputStream = new FileInputStream( file ) )
055 *      {
056 *          …
057 *      }
058 *      catch( final FileNotFoundException e )
059 *      {
060 *          throw new UnexpectedExceptionError( e );
061 *      }
062 *  }</pre></div>
063 *  <p>Although the code checked that the file exists, it could have vanished
064 *  just before it was opened.</p>
065 *  <p>Previously, this error was named {@code UnexpectedExceptionError}, but
066 *  the current name apparently fits better with the intention.</p>
067 *
068 *  @author Thomas Thrien - thomas.thrien@tquadrat.org
069 *  @version $Id: UnexpectedExceptionError.java 1293 2026-10-16 13:12:15Z tquadrat $
070 *  @since 0.25.15
071 *
072 *  @UMLGraph.link
073 */
074@ClassVersion( sourceVersion = "$Id: UnexpectedExceptionError.java 1293 2026-10-16 13:12:15Z tquadrat $" )
075@API( status = STABLE, since = "0.0.5" )
076public sealed class UnlikelyExceptionError extends AssertionError
077    permits ImpossibleExceptionError
078{
079        /*-----------*\
080    ====** Constants **========================================================
081        \*-----------*/
082    /**
083     *  The message for this exception.
084     */
085    private static final String MSG_UnexpectedException = "The Exception '%1$s' was not expected to occur in this context";
086
087        /*------------------------*\
088    ====** Static Initialisations **===========================================
089        \*------------------------*/
090    /**
091     *  The serial version UID for objects of this class: {@value}.
092     *
093     *  @hidden
094     */
095    @Serial
096    private static final long serialVersionUID = 2233464685783981770L;
097
098        /*--------------*\
099    ====** Constructors **=====================================================
100        \*--------------*/
101    /**
102     *  <p>{@summary {@constructor}} The message is a constant, only
103     *  the causing exception can be given.</p>
104     *
105     *  @param  cause   The causing exception.
106     */
107    public UnlikelyExceptionError( final Throwable cause )
108    {
109        super( format( MSG_UnexpectedException, requireNonNullArgument( cause, "cause" ).getClass().getName() ) , cause );
110    }   //  UnexpectedExceptionError()
111
112    /**
113     *  <p>{@summary {@constructor}} This constructor should be used in
114     *  cases where an enhanced message is useful or necessary.</p>
115     *
116     *  @param  message The message for the error.
117     *  @param  cause   The causing exception.
118     */
119    public UnlikelyExceptionError( final String message, final Throwable cause )
120    {
121        super( nonNull( message ) && !message.isEmpty() ? message : format( MSG_UnexpectedException, requireNonNullArgument( cause, "cause" ).getClass().getName() ), requireNonNullArgument( cause, "cause" ) );
122    }   //  UnexpectedExceptionError()
123}
124//  class UnexpectedExceptionError
125
126/*
127 *  End of File
128 */