1 /*
  2  * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package oracle.code.json;
 27 
 28 import oracle.code.json.impl.JsonNumberImpl;
 29 
 30 import java.math.BigDecimal;
 31 import java.math.BigInteger;
 32 
 33 /**
 34  * The interface that represents JSON number, an arbitrary-precision
 35  * number represented in base 10 using decimal digits.
 36  * <p>
 37  * A {@code JsonNumber} can be produced by {@link Json#parse(String)}.
 38  * Alternatively, {@link #of(double)} and its overloads can be used to obtain
 39  * a {@code JsonNumber} from a {@code Number}.
 40  * When a JSON number is parsed, a {@code JsonNumber} object is created
 41  * as long as the parsed value adheres to the JSON number
 42  * <a href="https://datatracker.ietf.org/doc/html/rfc8259#section-6">
 43  * syntax</a>. The value of the {@code JsonNumber}
 44  * can be retrieved from {@link #toString()} as the string representation
 45  * from which the JSON number is originally parsed, with
 46  * {@link #toNumber()} as a {@code Number} instance, or with
 47  * {@link #toBigDecimal()}.
 48  *
 49  * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-6 RFC 8259:
 50  *      The JavaScript Object Notation (JSON) Data Interchange Format - Numbers
 51  * @since 99
 52  */
 53 public non-sealed interface JsonNumber extends JsonValue {
 54 
 55     /**
 56      * {@return the {@code Number} parsed or translated from the
 57      * {@link #toString string representation} of this {@code JsonNumber}}
 58      * <p>
 59      * This method operates on the string representation and depending on that
 60      * representation computes and returns an instance of {@code Long}, {@code BigInteger},
 61      * {@code Double}, or {@code BigDecimal}.
 62      * <p>
 63      * If the string representation is the decimal string representation of
 64      * a {@code long} value, parsable by {@link Long#parseLong(String)},
 65      * then that {@code long} value is returned in its boxed form as {@code Long}.
 66      * Otherwise, if the string representation is the decimal string representation of a
 67      * {@code BigInteger}, translatable by {@link BigInteger#BigInteger(String)},
 68      * then that {@code BigInteger} is returned.
 69      * Otherwise, if the string representation is the decimal string representation of
 70      * a {@code double} value, parsable by {@link Double#parseDouble(String)},
 71      * and the {@code double} value is not {@link Double#isInfinite() infinite}, then that
 72      * {@code double} value is returned in its boxed form as {@code Double}.
 73      * Otherwise, and in all other cases, the string representation is the decimal string
 74      * representation of a {@code BigDecimal}, translatable by
 75      * {@link BigDecimal#BigDecimal(String)}, and that {@code BigDecimal} is
 76      * returned.
 77      * <p>
 78      * The computation may not preserve all information in the string representation.
 79      * In all of the above cases one or more leading zero digits are not preserved.
 80      * In the third case, returning {@code Double}, decimal to binary conversion may lose
 81      * decimal precision, and will not preserve one or more trailing zero digits in the fraction
 82      * part.
 83      *
 84      * @apiNote
 85      * Pattern matching can be used to match against {@code Long},
 86      * {@code Double}, {@code BigInteger}, or {@code BigDecimal} reference
 87      * types. For example:
 88      * {@snippet lang=java:
 89      * switch(jsonNumber.toNumber()) {
 90      *     case Long l -> { ... }
 91      *     case Double d -> { ... }
 92      *     case BigInteger bi -> { ... }
 93      *     case BigDecimal bd -> { ... }
 94      *     default -> { } // should not happen
 95      * }
 96      *}
 97      * @throws NumberFormatException if the {@code Number} cannot be parsed or translated from the string representation
 98      * @see #toBigDecimal()
 99      * @see #toString()
100      */
101     Number toNumber();
102 
103     /**
104      * {@return the {@code BigDecimal} translated from the
105      * {@link #toString string representation} of this {@code JsonNumber}}
106      * <p>
107      * The string representation is the decimal string representation of a
108      * {@code BigDecimal}, translatable by {@link BigDecimal#BigDecimal(String)},
109      * and that {@code BigDecimal} is returned.
110      * <p>
111      * The translation may not preserve all information in the string representation.
112      * The sign is not preserved for the decimal string representation {@code -0.0}. One or more
113      * leading zero digits are not preserved.
114      *
115      * @throws NumberFormatException if the {@code BigDecimal} cannot be translated from the string representation
116      */
117     BigDecimal toBigDecimal();
118 
119     /**
120      * Creates a JSON number whose string representation is the
121      * decimal string representation of the given {@code double} value,
122      * produced by applying the value to {@link Double#toString(double)}.
123      *
124      * @param num the given {@code double} value.
125      * @return a JSON number created from a {@code double} value
126      * @throws IllegalArgumentException if the given {@code double} value
127      * is {@link Double#isNaN() NaN} or is {@link Double#isInfinite() infinite}.
128      */
129     static JsonNumber of(double num) {
130         // non-integral types
131         return new JsonNumberImpl(num);
132     }
133 
134     /**
135      * Creates a JSON number whose string representation is the
136      * decimal string representation of the given {@code long} value,
137      * produced by applying the value to {@link Long#toString(long)}.
138      *
139      * @param num the given {@code long} value.
140      * @return a JSON number created from a {@code long} value
141      */
142     static JsonNumber of(long num) {
143         // integral types
144         return new JsonNumberImpl(num);
145     }
146 
147     /**
148      * Creates a JSON number whose string representation is the
149      * string representation of the given {@code BigInteger} value.
150      *
151      * @param num the given {@code BigInteger} value.
152      * @return a JSON number created from a {@code BigInteger} value
153      */
154     static JsonNumber of(BigInteger num) {
155         return new JsonNumberImpl(num);
156     }
157 
158     /**
159      * Creates a JSON number whose string representation is the
160      * string representation of the given {@code BigDecimal} value.
161      *
162      * @param num the given {@code BigDecimal} value.
163      * @return a JSON number created from a {@code BigDecimal} value
164      */
165     static JsonNumber of(BigDecimal num) {
166         return new JsonNumberImpl(num);
167     }
168 
169     /**
170      * {@return the decimal string representation of this {@code JsonNumber}}
171      *
172      * If this {@code JsonNumber} is created by parsing a JSON number in a JSON document,
173      * it preserves the string representation in the document, regardless of its
174      * precision or range. For example, a JSON number like
175      * {@code 3.141592653589793238462643383279} in the JSON document will be
176      * returned exactly as it appears.
177      * If this {@code JsonNumber} is created via one of the factory methods,
178      * such as {@link JsonNumber#of(double)}, then the string representation is
179      * specified by the factory method.
180      */
181     @Override
182     String toString();
183 
184     /**
185      * {@return true if the given {@code obj} is equal to this {@code JsonNumber}}
186      * The comparison is based on the string representation of this {@code JsonNumber},
187      * ignoring the case.
188      *
189      * @see #toString()
190      */
191     @Override
192     boolean equals(Object obj);
193 
194     /**
195      * {@return the hash code value of this {@code JsonNumber}} The returned hash code
196      * is calculated based on the string representation of this {@code JsonNumber},
197      * ignoring the case.
198      *
199      * @see #toString()
200      */
201     @Override
202     int hashCode();
203 }