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.jsonbuilder;
019
020import static org.apiguardian.api.API.Status.STABLE;
021
022import java.util.Formattable;
023import java.util.Formatter;
024
025import org.apiguardian.api.API;
026import org.tquadrat.foundation.annotation.ClassVersion;
027
028/**
029 *  <p>{@summary This interface describes the base for all the JSON
030 *  datatypes.}</p>
031 *  <p>{@code JSONValue} implements
032 *  {@link Formattable}
033 *  for the implementation of pretty-printed output through
034 *  {@code String.format( "%s", value )} or similar.</p>
035 *  <p>{@link #formatTo(Formatter,int,int,int)}
036 *  ignores the arguments {@code flags} and {@code precision}, while the
037 *  {@code width} argument is used internally. Therefore, a call like
038 *  {@code String.format( "%10s", value )} may result in some unexpected
039 *  output.</p>
040 *
041 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
042 *  @version $Id: JSONValue.java 1258 2026-06-04 18:33:06Z tquadrat $
043 *  @since 0.25.0
044 *
045 *  @UMLGraph.link
046 */
047@ClassVersion( sourceVersion = "$Id: JSONValue.java 1258 2026-06-04 18:33:06Z tquadrat $" )
048@API( status = STABLE, since = "0.25.0" )
049public sealed interface JSONValue extends Formattable
050    permits JSONArray, JSONLiteral, JSONNumber, JSONObject, JSONString
051{
052        /*---------*\
053    ====** Methods **==========================================================
054        \*---------*/
055    /**
056     *  <p>{@summary Returns this JSON value as
057     *  {@link JSONArray},
058     *  assuming that this value represents a JSON array.} If this is not the
059     *  case, an
060     *  {@link IllegalStateException}
061     *  is thrown.
062     *
063     *  @return This {@code JSONValue} instance as a
064     *      {@link JSONArray}.
065     *  @throws IllegalStateException   This JSON value is not a JSON array.
066     */
067    @SuppressWarnings( "ClassReferencesSubclass" )
068    public default JSONArray asArray()
069    {
070        if( !isArray() ) throw new IllegalStateException( "Not a JSONArray: %s".formatted( this.toString() ) );
071
072        //---* Done *----------------------------------------------------------
073        return (JSONArray) this;
074    }   //  asArray()
075
076    /**
077     *  <p>{@summary Returns this JSON value as
078     *  {@linkplain JSONLiteral JSON literals}
079     *  {@link JSONLiteral#FALSE false}
080     *  or
081     *  {@link JSONLiteral#TRUE true},
082     *  assuming that this value represents a JSON Boolean.} If this is not the
083     *  case, an
084     *  {@link IllegalStateException}
085     *  is thrown.
086     *
087     *  @return This {@code JSONValue} instance as a
088     *      {@link JSONLiteral}.
089     *  @throws IllegalStateException   This JSON value is not a JSON Boolean.
090     */
091    @SuppressWarnings( "ClassReferencesSubclass" )
092    public default JSONLiteral asBoolean()
093    {
094        if( !isBoolean() ) throw new IllegalStateException( "Not a JSON Boolean: %s".formatted( this.toString() ) );
095
096        //---* Done *----------------------------------------------------------
097        return (JSONLiteral) this;
098    }   //  asBoolean()
099
100    /**
101     *  <p>{@summary Returns this JSON value as
102     *  {@link JSONNumber},
103     *  assuming that this value represents a JSON number.} If this is not the
104     *  case, an
105     *  {@link IllegalStateException}
106     *  is thrown.
107     *
108     *  @return This {@code JSONValue} instance as a
109     *      {@link JSONNumber}.
110     *  @throws IllegalStateException   This JSON value is not a JSON String.
111     */
112    @SuppressWarnings( "ClassReferencesSubclass" )
113    public default JSONNumber asNumber()
114    {
115        if( !isNumber() ) throw new IllegalStateException( "Not a JSONNumber: %s".formatted( this.toString() ) );
116
117        //---* Done *----------------------------------------------------------
118        return (JSONNumber) this;
119    }   //  asNumber()
120
121    /**
122     *  <p>{@summary Returns this JSON value as
123     *  {@link JSONObject},
124     *  assuming that this value represents a JSON object.} If this is not the
125     *  case, an
126     *  {@link IllegalStateException}
127     *  is thrown.
128     *
129     *  @return This {@code JSONValue} instance as a
130     *      {@link JSONObject}.
131     *  @throws IllegalStateException   This JSON value is not a JSON object.
132     */
133    @SuppressWarnings( "ClassReferencesSubclass" )
134    public default JSONObject asObject()
135    {
136        if( !isObject() ) throw new IllegalStateException( "Not a JSONObject: %s".formatted( this.toString() ) );
137
138        //---* Done *----------------------------------------------------------
139        return (JSONObject) this;
140    }   //  asObject()
141
142    /**
143     *  <p>{@summary Returns this JSON value as
144     *  {@link JSONString},
145     *  assuming that this value represents a JSON String.} If this is not the
146     *  case, an
147     *  {@link IllegalStateException}
148     *  is thrown.
149     *
150     *  @return This {@code JSONValue} instance as a
151     *      {@link JSONString}.
152     *  @throws IllegalStateException   This JSON value is not a JSON String.
153     */
154    @SuppressWarnings( "ClassReferencesSubclass" )
155    public default JSONString asString()
156    {
157        if( !isString() ) throw new IllegalStateException( "Not a JSONString: %s".formatted( this.toString() ) );
158
159        //---* Done *----------------------------------------------------------
160        return (JSONString) this;
161    }   //  asString()
162
163    /**
164     *  {@inheritDoc}
165     */
166    @Override
167    public void formatTo( final Formatter formatter, final int flags, final int width, final int precision );
168
169    /**
170     *  <p>{@summary Detects whether this value represents a boolean
171     *  value.}</p>
172     *
173     *  @return {@true} if this value represents either the
174     *      {@linkplain JSONLiteral JSON literal}
175     *      {@link JSONLiteral#TRUE true}
176     *      or
177     *      {@link JSONLiteral#FALSE}.
178     */
179    public default boolean isBoolean() { return false; }
180
181    /**
182     *  <p>{@summary Detects whether this value represents a JSON array.} If
183     *  this is the case, this value is an instance of
184     *  {@link JSONArray}.</p>
185     *
186     *  @return {@true} if this value is an instance of
187     *      {@link JSONArray}, {@false} otherwise.
188     */
189    @SuppressWarnings( {"InstanceofThis", "ClassReferencesSubclass"} )
190    public default boolean isArray() { return this instanceof JSONArray; }
191
192    /**
193     *  <p>{@summary Detects whether this value represents the JSON literal
194     *  {@false}.}</p>
195     *
196     *  @return {@true} if this value represents the
197     *      {@linkplain JSONLiteral JSON literal}
198     *      {@link JSONLiteral#FALSE false}.
199     */
200    public default boolean isFalse() { return false; }
201
202    /**
203     *  <p>{@summary Detects whether this value represents the JSON literal
204     *  {@null}.}
205     *
206     *  @return {@true} if this value represents the
207     *      {@linkplain JSONLiteral JSON literal}
208     *      {@link JSONLiteral#NULL null}.
209     */
210    public default boolean isNull() { return false; }
211
212    /**
213     *  <p>{@summary Detects whether this value represents a JSON number.} If
214     *  this is the case, this value is an instance of
215     *  {@link JSONNumber}.</p>
216     *
217     *  @return {@true} if this value is an instance of
218     *      {@link JSONObject}, {@false} otherwise.
219     */
220    @SuppressWarnings( {"InstanceofThis", "ClassReferencesSubclass"} )
221    public default boolean isNumber() { return this instanceof JSONNumber; }
222
223    /**
224     *  <p>{@summary Detects whether this value represents a JSON object.} If
225     *  this is the case, this value is an instance of
226     *  {@link JSONObject}.</p>
227     *
228     *  @return {@true} if this value is an instance of
229     *      {@link JSONObject}, {@false} otherwise.
230     */
231    @SuppressWarnings( {"InstanceofThis", "ClassReferencesSubclass"} )
232    public default boolean isObject() { return this instanceof JSONObject; }
233
234    /**
235     *  <p>{@summary Detects whether this value represents a JSON string.} If
236     *  this is the case, this value is an instance of
237     *  {@link JSONString}.</p>
238     *
239     *  @return {@true} if this value is an instance of
240     *      {@link JSONString}, {@false} otherwise.
241     */
242    @SuppressWarnings( {"InstanceofThis", "ClassReferencesSubclass"} )
243    public default boolean isString() { return this instanceof JSONString; }
244
245    /**
246     *  <p>{@summary Detects whether this value represents the JSON literal
247     *  {@true}.}</p>
248     *
249     *  @return {@true} if this value represents the
250     *      {@linkplain JSONLiteral JSON literal}
251     *      {@link JSONLiteral#TRUE true}.
252     */
253    public default boolean isTrue() { return false; }
254
255    /**
256     *  {@inheritDoc}
257     */
258    @Override
259    public String toString();
260}
261//  interface JSONValue
262
263/*
264 *  End of File
265 */