001package Torello.Java.JSON;
002
003import javax.json.*;
004import java.lang.reflect.*;
005import java.math.*;
006
007import java.util.function.Function;
008
009import static javax.json.JsonValue.ValueType.*;
010import static Torello.Java.JSON.JFlag.*;
011import static Torello.Java.JSON.RJInternal.*;
012
013/**
014 * Builds on the J2EE Standard Release JSON Parsing Tools by providing additional
015 * help with converting JSON Data into <B STYLE='color: red'>Java Primitive-Types</B>
016 * 
017 * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE>
018 * <EMBED CLASS='external-html' DATA-CH=char DATA-FILE-ID=JAVA_LANG_CHAR>
019 * 
020 * @see Json
021 * @see JsonObject
022 * @see JsonArray
023 */
024@Torello.JavaDoc.StaticFunctional
025@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI")
026@SuppressWarnings("cast")
027public class ReadPrimJSON
028{
029    // This is a static class.  Has no program state.
030    private ReadPrimJSON() { }
031
032
033    // ********************************************************************************************
034    // ********************************************************************************************
035    // int
036    // ********************************************************************************************
037    // ********************************************************************************************
038
039
040    /**
041     * Retrieve a {@link JsonArray} element, and transform it to an {@code 'int'} primitive
042     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=int DATA-M=intValueExact>
043     * 
044     * @param ja    Any instance of {@link JsonArray}
045     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
046     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
047     * 
048     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
049     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
050     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
051     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
052     * 
053     * @see RJInternal#GET(JsonArray, int, Class, Function)
054     * @see JsonNumber#intValueExact()
055     */
056    public static int getInt(JsonArray ja, int index)
057    { return GET(ja, index, int.class, JsonNumber::intValueExact); }
058
059    /**
060     * Extract a {@link JsonObject} property, and transform it to an {@code 'int'} primitive
061     * <EMBED CLASS=defs DATA-TYPE=int DATA-JTYPE=JsonNumber DATA-M=intValueExact>
062     * 
063     * @param jo            Any instance of {@link JsonObject}
064     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
065     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
066     * 
067     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
068     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
069     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
070     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
071     * 
072     * @see RJInternal#GET(JsonObject, String, Class, Function)
073     * @see JsonNumber#intValueExact()
074     */
075    public static int getInt(JsonObject jo, String propertyName)
076    { return GET(jo, propertyName, int.class, JsonNumber::intValueExact); }
077
078
079    // ********************************************************************************************
080    // ********************************************************************************************
081    // long
082    // ********************************************************************************************
083    // ********************************************************************************************
084
085
086    /**
087     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'long'} primitive
088     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=long DATA-M=longValueExact>
089     * 
090     * @param ja    Any instance of {@link JsonArray}
091     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
092     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
093     * 
094     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
095     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
096     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
097     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
098     * 
099     * @see RJInternal#GET(JsonArray, int, Class, Function)
100     * @see JsonNumber#longValueExact()
101     */
102    public static long getLong(JsonArray ja, int index)
103    { return GET(ja, index, long.class, JsonNumber::longValueExact); }
104
105    /**
106     * Extract a {@link JsonObject} property, and transform it to a {@code 'long'} primitive
107     * <EMBED CLASS=defs DATA-TYPE=long DATA-JTYPE=JsonNumber DATA-M=longValueExact>
108     * 
109     * @param jo            Any instance of {@link JsonObject}
110     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
111     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
112     * 
113     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
114     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
115     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
116     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
117     * 
118     * @see RJInternal#GET(JsonObject, String, Class, Function)
119     * @see JsonNumber#longValueExact()
120     */
121    public static long getLong(JsonObject jo, String propertyName)
122    { return GET(jo, propertyName, long.class, JsonNumber::longValueExact); }
123
124
125    // ********************************************************************************************
126    // ********************************************************************************************
127    // short
128    // ********************************************************************************************
129    // ********************************************************************************************
130
131
132    /**
133     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'short'} primitive
134     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=short DATA-M=shortValueExact>
135     * 
136     * @param ja    Any instance of {@link JsonArray}
137     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
138     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
139     * 
140     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
141     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
142     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
143     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
144     * 
145     * @see RJInternal#GET(JsonArray, int, Class, Function)
146     * @see JsonNumber#bigDecimalValue()
147     */
148    public static short getShort(JsonArray ja, int index)
149    { return GET(ja, index, short.class, jn -> jn.bigDecimalValue().shortValueExact()); }
150
151    /**
152     * Extract a {@link JsonObject} property, and transform it to a {@code 'short'} primitive
153     * <EMBED CLASS=defs DATA-TYPE=short DATA-JTYPE=JsonNumber DATA-M=shortValueExact>
154     * 
155     * @param jo            Any instance of {@link JsonObject}
156     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
157     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
158     * 
159     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
160     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
161     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
162     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
163     * 
164     * @see RJInternal#GET(JsonObject, String, Class, Function)
165     * @see JsonNumber#bigDecimalValue()
166     */
167    public static short getShort(JsonObject jo, String propertyName)
168    { return GET(jo, propertyName, short.class, jn -> jn.bigDecimalValue().shortValueExact()); }
169
170
171    // ********************************************************************************************
172    // ********************************************************************************************
173    // byte
174    // ********************************************************************************************
175    // ********************************************************************************************
176
177
178    /**
179     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'byte'} primitive
180     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=byte DATA-M=byteValueExact>
181     * 
182     * @param ja    Any instance of {@link JsonArray}
183     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
184     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
185     * 
186     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
187     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
188     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
189     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
190     * 
191     * @see RJInternal#GET(JsonArray, int, Class, Function)
192     * @see JsonNumber#bigDecimalValue()
193     */
194    public static byte getByte(JsonArray ja, int index)
195    { return GET(ja, index, byte.class, jn -> jn.bigDecimalValue().byteValueExact()); }
196
197    /**
198     * Extract a {@link JsonObject} property, and transform it to a {@code 'byte'} primitive
199     * <EMBED CLASS=defs DATA-TYPE=byte DATA-JTYPE=JsonNumber DATA-M=byteValueExact>
200     * 
201     * @param jo            Any instance of {@link JsonObject}
202     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
203     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
204     * 
205     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
206     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX>
207     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
208     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
209     * 
210     * @see RJInternal#GET(JsonObject, String, Class, Function)
211     * @see JsonNumber#bigDecimalValue()
212     */
213    public static byte getByte(JsonObject jo, String propertyName)
214    { return GET(jo, propertyName, byte.class, jn -> jn.bigDecimalValue().byteValueExact()); }
215
216
217    // ********************************************************************************************
218    // ********************************************************************************************
219    // double
220    // ********************************************************************************************
221    // ********************************************************************************************
222
223
224    /**
225     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'double'} primitive
226     * 
227     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=double DATA-M=doubleValue
228     *  DATA-INFINITY=Double>
229     * <EMBED CLASS='external-html' DATA-FILE-ID=JR_FLOAT>
230     * 
231     * @param ja    Any instance of {@link JsonArray}
232     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
233     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
234     * 
235     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
236     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
237     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX_INF>
238     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
239     * 
240     * @see RJInternal#GET(JsonArray, int, Class, Function)
241     * @see RJInternal#DOUBLE_WITH_CHECK(JsonNumber)
242     */
243    public static double getDouble(JsonArray ja, int index)
244    { return GET(ja, index, double.class, RJInternal::DOUBLE_WITH_CHECK); }
245
246    /**
247     * Extract a {@link JsonObject} property, and transform it to a {@code 'double'} primitive
248     * 
249     * <EMBED CLASS=defs DATA-TYPE=double DATA-JTYPE=JsonNumber DATA-M=doubleValue
250     *  DATA-INFINITY=Double>
251     * <EMBED CLASS='external-html' DATA-FILE-ID=JR_FLOAT>
252     * 
253     * @param jo            Any instance of {@link JsonObject}
254     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
255     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
256     * 
257     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
258     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX_INF>
259     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
260     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
261     * 
262     * @see RJInternal#GET(JsonObject, String, Class, Function)
263     * @see RJInternal#DOUBLE_WITH_CHECK(JsonNumber)
264     */
265    public static double getDouble(JsonObject jo, String propertyName)
266    { return GET(jo, propertyName, double.class, RJInternal::DOUBLE_WITH_CHECK); }
267
268
269    // ********************************************************************************************
270    // ********************************************************************************************
271    // float
272    // ********************************************************************************************
273    // ********************************************************************************************
274
275
276    /**
277     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'float'} primitive
278     * 
279     * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE=float DATA-M=floatValue
280     *  DATA-INFINITY=Float>
281     * <EMBED CLASS='external-html' DATA-FILE-ID=JR_FLOAT>
282     * 
283     * @param ja    Any instance of {@link JsonArray}
284     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
285     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
286     * 
287     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
288     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
289     * @throws JsonArithmeticArrException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX_INF>
290     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
291     * 
292     * @see RJInternal#GET(JsonArray, int, Class, Function)
293     * @see RJInternal#FLOAT_WITH_CHECK(JsonNumber)
294     */
295    public static float getFloat(JsonArray ja, int index)
296    { return GET(ja, index, float.class, RJInternal::FLOAT_WITH_CHECK); }
297
298    /**
299     * Extract a {@link JsonObject} property, and transform it to a {@code 'float'} primitive
300     * 
301     * <EMBED CLASS=defs DATA-TYPE=float DATA-JTYPE=JsonNumber DATA-M=floatValue
302     *  DATA-INFINITY=Float>
303     * <EMBED CLASS='external-html' DATA-FILE-ID=JR_FLOAT>
304     * 
305     * @param jo            Any instance of {@link JsonObject}
306     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
307     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
308     * 
309     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
310     * @throws JsonArithmeticObjException    <EMBED CLASS='external-html' DATA-FILE-ID=JR_JAEX_INF>
311     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
312     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
313     * 
314     * @see RJInternal#GET(JsonObject, String, Class, Function)
315     * @see RJInternal#FLOAT_WITH_CHECK(JsonNumber)
316     */
317    public static float getFloat(JsonObject jo, String propertyName)
318    { return GET(jo, propertyName, float.class, RJInternal::FLOAT_WITH_CHECK); }
319
320
321    // ********************************************************************************************
322    // ********************************************************************************************
323    // boolean
324    // ********************************************************************************************
325    // ********************************************************************************************
326
327
328    /**
329     * Retrieve a {@link JsonArray} element, and transform it to a {@code 'boolean'} primitive
330     * <EMBED CLASS=defs DATA-JTYPE='JSON-BOOLEAN' DATA-TYPE=boolean>
331     * 
332     * @param ja    Any instance of {@link JsonArray}
333     * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA>
334     * @return      <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JA>
335     * 
336     * @throws IndexOutOfBoundsException     If {@code 'index'} is out of the bounds of {@code 'ja'}
337     * @throws JsonTypeArrException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX>
338     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPAEX>
339     * 
340     * @see ReadBoxedJSON#getBoolean(JsonArray, int)
341     */
342    public static boolean getBoolean(JsonArray ja, int index)
343    {
344        // This method (defined below) allows for null-returns, but "getBoolean" does not.  
345        // "getBOOLEAN" will only return null if the actual array location 'index' actually has
346        // the word 'null' listed.
347
348        Boolean ret = ReadBoxedJSON.getBoolean(ja, index);
349
350        // In that case, throw the Null-Primitive Exception
351        if (ret == null) throw new JsonNullPrimitiveArrException
352                (ja, index, TRUE, boolean.class);
353
354        return ret;
355    }
356
357    /**
358     * Extract a {@link JsonObject} property, and transform it to a {@code 'boolean'} primitive
359     * <EMBED CLASS=defs DATA-TYPE=boolean DATA-JTYPE='JSON-BOOLEAN'>
360     * 
361     * @param               jo Any instance of {@link JsonObject}
362     * @param propertyName  <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO>
363     * @return              <EMBED CLASS='external-html' DATA-FILE-ID=JR_PRRET_JO>
364     * 
365     * @throws JsonPropMissingException      <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX_PR>
366     * @throws JsonTypeObjException          <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX>
367     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNPOEX>
368     * 
369     * @see ReadBoxedJSON#getBoolean(JsonObject, String, boolean)
370     */
371    public static boolean getBoolean(JsonObject jo, String propertyName)
372    {
373        // Since 'false' is passed, a null return-value will mean that the property was actually
374        // set to null in the JsonObject itself.  (It *IS NOT* missing, it is present, but rather
375        // declared null)
376
377        Boolean ret = ReadBoxedJSON.getBoolean(jo, propertyName, false);
378
379        if (ret == null) throw new JsonNullPrimitiveObjException
380            (jo, propertyName, TRUE, boolean.class);
381
382        // NOTE: Java's Type-Stuff can automatically convert Boolean -> boolean
383        else return ret;
384    }
385}