001package Torello.Java.Additional;
002
003import javax.json.*;
004import java.math.*;
005
006import static javax.json.JsonValue.ValueType.*;
007import static Torello.Java.Additional.JFlag.*;
008
009import java.util.function.Function;
010
011/**
012 * Class which provides a series of helper functions for both {@link ReadJSON} and
013 * {@link ReadJSON.XL}.
014 * 
015 * <BR /><BR />The helpers for class {@link ReadArrJSON} are kept inside that class, and do not
016 * appear in this one.
017 * 
018 * <BR /><BR /><B CLASS=JDRedLabel>IMPORTANT:</B>
019 * <BR />100% of the helper-methods that appear here are protected, and cannot be accessed
020 * outside of this package.  They are included in the documentation solely for the purposes of
021 * (<I>if you happen to be interested</I>) letting you know how the JSON-Tools work.
022 */
023@Torello.HTML.Tools.JavaDoc.StaticFunctional
024public class RJInternal
025{
026    private RJInternal() { }
027
028
029    // ********************************************************************************************
030    // ********************************************************************************************
031    // "Helpers for the Helpers for the Helpers"
032    // ********************************************************************************************
033    // ********************************************************************************************
034
035
036    /**
037     * Generates a {@code JsonException} with a uniformly-consisten error-message.
038     
039    protected static void throwJsonBindingException(Class<?> c)
040    {
041        throw new JsonException(
042            "The class which was passed to parameter 'c' [" + c.getName() + "] does not " +
043            "appear to have a constructor with precisely one parameter of type JsonObject."
044        );
045    }
046    */
047
048    /**
049     * Helper Method that generates an {@code ArithmeticException} with a uniformly-consistent
050     * exception message
051     * @param jn A Java {@code javax.json.JsonNumber} whose magnitude is too large.
052     * @throws ArithmeticException
053     */
054    protected static void throwAE_INFINITY
055        (JsonNumber jn, String primTypeName, boolean positiveOrNegative)
056    {
057        throw new ArithmeticException(
058            "When attempting to conver the JsonNumber [" + jn.toString() + "] to a " +
059            primTypeName + " primitive, the number had a magnitude that was too large: " +
060            (positiveOrNegative ? "Positive" : "Negative") + " Infinity was returned."
061        );
062    }
063
064    /**
065     * Helper Method that generates an {@code ArithmeticException} with a uniformly-consistent
066     * exception message
067     * @param bd A Java {@code java.math.BigDecimal} whose magnitude is too large.
068     * @throws ArithmeticException
069     */
070    protected static void throwAE_INFINITY
071        (BigDecimal bd, String primTypeName, boolean positiveOrNegative)
072    {
073        throw new ArithmeticException(
074            "When attempting to conver the JsonNumber [" + bd.toString() + "] to a " +
075            primTypeName + " primitive, the number had a magnitude that was too large: " +
076            (positiveOrNegative ? "Positive" : "Negative") + " Infinity was returned."
077        );
078    }
079
080    /**
081     * Converts a {@link JsonNumber} into a Java {@code double}
082     * @param jn Any {@link JsonNumber}
083     * @return java {@code double} primitive
084     * @throws JsonArithmeticException If infinity is returned from the call to
085     * {@code BigDecimal.doubleValue()}
086     * @see JsonNumber#bigDecimalValue()
087     */
088    protected static double DOUBLE_WITH_CHECK(JsonNumber jn)
089    { return DOUBLE_WITH_CHECK(jn.bigDecimalValue()); }
090
091    /**
092     * Converts a {@code BigDecimal} into a Java {@code double}
093     * @param bd Any {@code BigDecimal}
094     * @return Java {@code double} primitive
095     * @throws JsonArithmeticException If infinity is returned from the call to
096     * {@code code BigDecimal.doubleValue()}
097     */
098    protected static double DOUBLE_WITH_CHECK(BigDecimal bd)
099    {
100        double ret = bd.doubleValue();
101
102        if (ret == Double.NEGATIVE_INFINITY) throwAE_INFINITY(bd, "double", false);
103        if (ret == Double.POSITIVE_INFINITY) throwAE_INFINITY(bd, "double", true);
104
105        return ret;
106    }
107
108    /**
109     * Converts a {@link JsonNumber} into a Java {@code float}
110     * @param jn Any {@link JsonNumber}
111     * @return java {@code float} primitive
112     * @throws JsonArithmeticException If infinity is returned from the call to
113     * {@code BigDecimal.floatValue()}
114     * @see JsonNumber#bigDecimalValue()
115     */
116    protected static float FLOAT_WITH_CHECK(JsonNumber jn)
117    { return FLOAT_WITH_CHECK(jn.bigDecimalValue()); }
118
119    /**
120     * Converts a {@code BigDecimal} into a Java {@code float}
121     * @param bd Any {@code BigDecimal}
122     * @return Java {@code float} primitive
123     * @throws JsonArithmeticException If infinity is returned from the call to
124     * {@code code BigDecimal.floatValue()}
125     */
126    protected static float FLOAT_WITH_CHECK(BigDecimal bd)
127    {
128        float ret = bd.floatValue();
129
130        if (ret == Float.NEGATIVE_INFINITY) throwAE_INFINITY(bd, "float", false);
131        if (ret == Float.POSITIVE_INFINITY) throwAE_INFINITY(bd, "float", true);
132
133        return ret;
134    }
135
136    /**
137     * Converts any {@link JsonNumber} into one of the inheriting subclasses of Java class
138     * {@code Number}
139     * @param jn Any {@link JsonNumber}
140     * @return The most appropriate intance of {@code java.lang.Number}
141     * @see ReadJSON#getNUMBER(JsonObject, String, int, Number)
142     * @see ReadJSON#getNUMBER(JsonArray, int, int, Number)
143     * @see JsonNumber#isIntegral()
144     * @see JsonNumber#bigIntegerValue()
145     * @see JsonNumber#bigDecimalValue()
146     */
147    protected static Number convertToNumber(JsonNumber jn)
148    {
149        if (jn.isIntegral())
150        {
151            BigInteger bi = jn.bigIntegerValue();
152            int        l  = bi.bitLength();
153
154            if (l <= 32) return Integer.valueOf(bi.intValue());
155            if (l <= 64) return Long.valueOf(bi.longValue());
156            return bi;
157        }
158        else
159        {
160            BigDecimal bd = jn.bigDecimalValue();
161
162            // This probably isn't the most efficient thing I've ever written, but I do not
163            // have the energy to stare at java.math.BigDecimal at the moment.  The JavaDoc for
164            // this JSON => Java-Type Conversion is quite intricate.  I will figure this out at
165            // at later date.
166
167            float f = bd.floatValue();
168            if ((f != Float.NEGATIVE_INFINITY) && (f != Float.POSITIVE_INFINITY)) return f;
169
170            double d = bd.doubleValue();
171            if ((f != Double.NEGATIVE_INFINITY) && (f != Double.POSITIVE_INFINITY)) return d;
172
173            return bd;
174        }
175    }
176
177    /**
178     * Converts any {@code java.lang.String} into one of the inheriting subclasses of Java class
179     * {@code Number}
180     * @param s Any {@code String}
181     * @return The most appropriate instance of {@code java.lang.Number}
182     * @throws NumberFormatException If the input {@code String} isn't properly formatted as a
183     * number.
184     * @see ReadJSON#parseNUMBER(JsonObject, String, int, Number, Function)
185     * @see ReadJSON#parseNUMBER(JsonArray, int, int, Number, Function)
186     */
187    protected static Number convertToNumber(String s)
188    { return convertToNumber(new BigDecimal(s.trim())); }
189
190    /**
191     * Converts any {@code java.math.BigDecimal} into one of the inheriting subclasses of
192     * {@code Number}.
193     * @param bd Any {@code BigDecimal}
194     * @return The most appropriate instance of {@code java.lang.Number}
195     */
196    protected static Number convertToNumber(BigDecimal bd)
197    {
198        if (bd.scale() == 0)
199        {
200            BigInteger bi = bd.toBigInteger();
201            int        l  = bi.bitLength();
202
203            if (l <= 32) return Integer.valueOf(bi.intValue());
204            if (l <= 64) return Long.valueOf(bi.longValue());
205            return bi;
206        }
207        else
208        {
209            // This probably isn't the most efficient thing I've ever written, but I do not
210            // have the energy to stare at java.math.BigDecimal at the moment.  The JavaDoc for
211            // this JSON => Java-Type Conversion is quite intricate.  I will figure this out at
212            // at later date.
213
214            float f = bd.floatValue();
215            if ((f != Float.NEGATIVE_INFINITY) && (f != Float.POSITIVE_INFINITY)) return f;
216
217            double d = bd.doubleValue();
218            if ((f != Double.NEGATIVE_INFINITY) && (f != Double.POSITIVE_INFINITY)) return d;
219
220            return bd;
221        }
222    }
223
224
225    // ********************************************************************************************
226    // ********************************************************************************************
227    // PRIMARY FOUR "GET" METHODS FOR NUMBERS
228    // ********************************************************************************************
229    // ********************************************************************************************
230
231
232    /**
233     * This is an internal helper method for retrieving an element from a {@link JsonArray},
234     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
235     * 
236     * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_T>
237     * @param ja Any instance of {@link JsonArray}
238     * @param index Any index into the array which holds a {@link JsonNumber}
239     * @param primitiveClass <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_PC>
240     * @param jsonTypeToJavaType <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTTJT>
241     * 
242     * @return The converted number, as an instance Generic-Parameter {@code 'T'}
243     * 
244     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html'
245     *  DATA-FILE-ID=JR_GET_JNPAEX>
246     * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTAEX>
247     * @throws JsonArithmeticArrException If there any arithmetic problems during the conversion
248     * @throws IndexOutOfBoundsException If {@code 'index'} is out of the bounds of {@code 'ja'}
249     * 
250     * @see ReadJSON#getInt(JsonArray, int)
251     * @see ReadJSON#getLong(JsonArray, int)
252     * @see ReadJSON#getShort(JsonArray, int)
253     * @see ReadJSON#getByte(JsonArray, int)
254     * @see ReadJSON#getDouble(JsonArray, int)
255     * @see ReadJSON#getFloat(JsonArray, int)
256     */
257    protected static <T> T GET(
258            JsonArray ja, int index, Class<T> primitiveClass,
259            Function<JsonNumber, T> jsonTypeToJavaType
260        )
261    {
262        // This will throw an IndexOutOfBoundsException if the index is out of bounds.
263        JsonValue jv = ja.get(index);
264
265        switch (jv.getValueType())
266        {
267            // This method allows for null-returns.  If Json-Null, return Java-Null.
268            case NULL: throw new JsonNullPrimitiveArrException
269                (ja, index, NUMBER, primitiveClass);
270
271            // This will throw ArithmeticException if it cannot be converted
272            case NUMBER:
273
274                // REMEMBER: The primary reason for this class is that MEANINGFUL ERROR MESSAGES
275                //           make Json-Binding a lot easer...  "JsonArithmeticException" has just
276                //           about everything that you need to know when debugging this stuff
277
278                try
279                    { return jsonTypeToJavaType.apply((JsonNumber) jv); }
280
281                catch (ArithmeticException ae)
282                {
283                    throw new JsonArithmeticArrException
284                        (ae, ja, index, NUMBER, jv, primitiveClass);
285                }
286
287            // The JsonValue at the specified array-index does not contain an JsonNumber.
288            default: throw new JsonTypeArrException
289                (ja, index, NUMBER, jv, primitiveClass);
290        }
291    }
292
293    /**
294     * This is an internal helper method for retrieving an element from a {@link JsonArray},
295     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
296     * 
297     * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_T>
298     * @param ja Any instance of {@link JsonArray}
299     * @param index Any index into the array which holds a {@link JsonNumber}
300     * @param jsonTypeToJavaType <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTTJT>
301     * 
302     * @return The converted number, as an instance Generic-Parameter {@code 'T'}
303     * 
304     * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTAEX>
305     * @throws JsonArithmeticArrException If there any arithmetic problems during the conversion
306     * @throws IndexOutOfBoundsException If {@code 'index'} is out of the bounds of {@code 'ja'}
307     * 
308     * @see ReadJSON#getINTEGER(JsonArray, int)
309     * @see ReadJSON#getLONG(JsonArray, int)
310     * @see ReadJSON#getSHORT(JsonArray, int)
311     * @see ReadJSON#getBYTE(JsonArray, int)
312     * @see ReadJSON#getDOUBLE(JsonArray, int)
313     * @see ReadJSON#getFLOAT(JsonArray, int)
314     */
315    protected static <T extends java.lang.Number> T GET
316        (JsonArray ja, int index, Function<JsonNumber, T> jsonTypeToJavaType, Class<T> returnClass)
317    {
318        // This will throw an IndexOutOfBoundsException if the index is out of bounds.
319        // Since this *IS NOT* a method with FLAGS, the user has no way to avoid this exception
320        // throw if, indeed, the index really is out of bounds!
321        //
322        // Using one of the 'FLAGS' variants of the 'GET' array-index, a user may request that
323        // either null or a default-value be returned.  Not with this version-of 'GET', though.
324
325        JsonValue jv = ja.get(index);
326
327        switch (jv.getValueType())
328        {
329            // This method allows for null-returns.  If Json-Null, return Java-Null.
330            case NULL: return null;
331
332            // This will throw ArithmeticException if it cannot be converted
333            case NUMBER:
334
335                // REMEMBER: The primary reason for this class is that MEANINGFUL ERROR MESSAGES
336                //           make Json-Binding a lot easer...  "JsonArithmeticException" has just
337                //           about everything that you need to know when debugging this stuff
338
339                try
340                    { return jsonTypeToJavaType.apply((JsonNumber) jv); }
341
342                catch (ArithmeticException ae)
343                {
344                    throw new JsonArithmeticArrException
345                        (ae, ja, index, NUMBER, jv, returnClass);
346                }
347
348            // The JsonValue at the specified array-index does not contain an JsonNumber.
349            default: throw new JsonTypeArrException
350                (ja, index, NUMBER, jv, returnClass);
351        }
352    }
353
354    /**
355     * This is an internal helper method for retrieving a property from a {@link JsonObject},
356     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
357     * 
358     * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_T>
359     * @param jo Any instance of {@link JsonObject}
360     * @param propertyName Any property name contained by {@code 'jo'}
361     * @param jsonTypeToJavaType <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTTJT>
362     * 
363     * @return The converted number, as an instance Generic-Parameter {@code 'T'}
364     * 
365     * @throws JsonNullPrimitiveObjException <EMBED CLASS='external-html'
366     *  DATA-FILE-ID=JR_GET_JNPOEX>
367     * @throws JsonPropMissingException If the property is missing, and {@code 'isOptional'}
368     * is {@code FALSE}.
369     * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTAEX>
370     * @throws JsonArithmeticObjException If there any arithmetic problems during the conversion
371     * 
372     * @see ReadJSON#getInt(JsonObject, String)
373     * @see ReadJSON#getLong(JsonObject, String)
374     * @see ReadJSON#getShort(JsonObject, String)
375     * @see ReadJSON#getByte(JsonObject, String)
376     * @see ReadJSON#getDouble(JsonObject, String)
377     * @see ReadJSON#getFloat(JsonObject, String)
378     */
379    protected static <T> T GET(
380            JsonObject jo, String propertyName, Class<T> primitiveClass,
381            Function<JsonNumber, T> jsonTypeToJavaType
382        )
383    {
384        // Here, a 'get' request was made for a property that isn't actually listed among the
385        // properties in the provided JsonObject.  Since this internal 'GET' is used by methods
386        // that are trying to return a Java Primitive (like 'int' or 'float'), then an exception
387        // has to be thrown.  The option of returning 'null' isn't possible here!
388    
389        if (! jo.containsKey(propertyName)) throw new JsonPropMissingException
390            (jo, propertyName, NUMBER, primitiveClass);
391
392        JsonValue jv = jo.get(propertyName);
393
394        switch (jv.getValueType())
395        {
396            // This method allows for null-returns.  If Json-Null, return Java-Null.
397            case NULL: throw new JsonNullPrimitiveObjException
398                (jo, propertyName, NUMBER, primitiveClass);
399
400            // This will throw ArithmeticException if this isn't a proper Java int
401            case NUMBER:
402
403                // REMEMBER: The primary reason for this class is that MEANINGFUL ERROR MESSAGES
404                //           make Json-Binding a lot easer...  "JsonArithmeticException" has just
405                //           about everything that you need to know when debugging this stuff
406
407                try
408                    { return jsonTypeToJavaType.apply((JsonNumber) jv); }
409
410                catch (ArithmeticException ae)
411                {
412                    throw new JsonArithmeticObjException
413                        (ae, jo, propertyName, NUMBER, jv, primitiveClass);
414                }
415
416            // The JsonObject property does not contain a JsonNumber.
417            default: throw new JsonTypeObjException
418                (jo, propertyName, NUMBER, jv, primitiveClass);
419        }
420    }
421
422    /**
423     * This is an internal helper method for retrieving a property from a {@link JsonObject},
424     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
425     * 
426     * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_T>
427     * @param jo Any instance of {@link JsonObject}
428     * @param propertyName Any property name contained by {@code 'jo'}
429     * @param isOptional Indicates whether {@code 'propertyName'} may be missing from {@code 'jo'}
430     * @param jsonTypeToJavaType <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTTJT>
431     * 
432     * @return The converted number, as an instance Generic-Parameter {@code 'T'}
433     * 
434     * @throws JsonPropMissingException If the property is missing, and {@code 'isOptional'}
435     * is {@code FALSE}.
436     * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_GET_JTAEX>
437     * @throws JsonArithmeticObjException If there any arithmetic problems during the conversion
438     * 
439     * @see ReadJSON#getINTEGER(JsonObject, String, boolean)
440     * @see ReadJSON#getLONG(JsonObject, String, boolean)
441     * @see ReadJSON#getSHORT(JsonObject, String, boolean)
442     * @see ReadJSON#getBYTE(JsonObject, String, boolean)
443     * @see ReadJSON#getDOUBLE(JsonObject, String, boolean)
444     * @see ReadJSON#getFLOAT(JsonObject, String, boolean)
445     */
446    protected static <T extends java.lang.Number> T GET(
447            JsonObject jo, String propertyName, boolean isOptional,
448            Function<JsonNumber, T> jsonTypeToJavaType, Class<T> returnClass
449        )
450    {
451        // Here, a 'get' request was made for a property that isn't actually listed among the
452        // properties in the provided JsonObject.  If 'isOptional' return null, otherwise throw
453
454        if (! jo.containsKey(propertyName))
455        {
456            if (isOptional) return null;
457
458            throw new JsonPropMissingException
459                (jo, propertyName, NUMBER, returnClass);
460        }
461
462        JsonValue jv = jo.get(propertyName);
463
464        switch (jv.getValueType())
465        {
466            // This method allows for null-returns.  If Json-Null, return Java-Null.
467            case NULL: return null;
468
469            // This will throw ArithmeticException if this isn't a proper Java int
470            case NUMBER:
471
472                // REMEMBER: The primary reason for this class is that MEANINGFUL ERROR MESSAGES
473                //           make Json-Binding a lot easer...  "JsonArithmeticException" has just
474                //           about everything that you need to know when debugging this stuff
475
476                try
477                    { return jsonTypeToJavaType.apply((JsonNumber) jv); }
478
479                catch (ArithmeticException ae)
480                {
481                    throw new JsonArithmeticObjException
482                        (ae, jo, propertyName, NUMBER, jv, returnClass);
483                }
484
485            // The JsonObject property does not contain a JsonNumber.
486            default: throw new JsonTypeObjException
487                (jo, propertyName, NUMBER, jv, returnClass);
488        }
489    }
490
491
492    // ********************************************************************************************
493    // ********************************************************************************************
494    // FLAG-CHECKER METHODS another section of "Helpers for the Helpers ..."
495    // ********************************************************************************************
496    // ********************************************************************************************
497
498
499    /**
500     * Flag Checker for {@code IndexOutOfBoundsException}.
501     * 
502     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
503     * and either returns the appropriate value accordingly, or throws
504     * {@code IndexOutOfBoundsException}.
505     * 
506     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
507     * 
508     * @param <T> If requested, the default-value is returned, and this is its type.
509     * 
510     * @return Can return either the user-provided default-value, or null depending on whether a
511     * match was found in the user's request settings ({@code 'FLAGS'}).
512     * 
513     * @throws IndexOutOfBoundsException If no flag was set specifying one of the two return-value
514     * options.
515     * 
516     * @see JFlag#RETURN_NULL_ON_IOB
517     * @see JFlag#RETURN_DEFVAL_ON_IOB
518     * @see JFlag#RETURN_NULL_ON_ANY_ALL
519     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
520     */
521    protected static <T> T IOOBEX(JsonArray ja, int index, T defaultValue, int FLAGS)
522    {
523        if ((FLAGS & RETURN_NULL_ON_IOB) != 0)          return null;
524        if ((FLAGS & RETURN_DEFVAL_ON_IOB) != 0)        return defaultValue;
525        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
526        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
527
528        ja.get(index); // Throws an IndexOutOfBoundsException
529
530        // If you have reached this statment, this method was not applied properly
531        throw new Torello.Java.UnreachableError();
532    }
533
534    /**
535     * Flag Checker for {@link JsonPropMissingException}
536     * 
537     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
538     * and either returns the appropriate value accordingly, or throws
539     * {@code JsonPropMissingException}.
540     * 
541     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
542     * 
543     * @param <T> If requested, the default-value is returned, and this is its type.
544     * 
545     * @return Can return either the user-provided default-value, or null depending on whether a
546     * match was found in the user's request settings ({@code 'FLAGS'}).
547     * 
548     * @throws JsonPropMissingException If no flag was set specifying one of the two return-value
549     * options.
550     * 
551     * @see JFlag#RETURN_NULL_ON_MISSING
552     * @see JFlag#RETURN_DEFVAL_ON_MISSING
553     * @see JFlag#RETURN_NULL_ON_ANY_ALL
554     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
555     */
556    protected static <T> T JPMEX(
557            JsonObject jo, String propertyName, T defaultValue, int FLAGS,
558            JsonValue.ValueType expectedType, Class<T> returnClass
559        )
560    {
561        if ((FLAGS & RETURN_NULL_ON_MISSING) != 0)      return null;
562        if ((FLAGS & RETURN_DEFVAL_ON_MISSING) != 0)    return defaultValue;
563        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
564        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
565
566        throw new JsonPropMissingException(jo, propertyName, expectedType, returnClass);
567    }
568
569    /**
570     * Flag Checker for {@link JsonNullArrException}
571     * 
572     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
573     * and either returns the appropriate value accordingly, or throws
574     * {@code JsonNullArrException}.
575     * 
576     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
577     * 
578     * @param <T> If requested, the default-value is returned, and this is its type.
579     * 
580     * @return Can return either the user-provided default-value, or null depending on whether a
581     * match was found in the user's request settings ({@code 'FLAGS'}).
582     * 
583     * @throws JsonNullArrException If no flag was set specifying one of the two return-value
584     * options.
585     * 
586     * @see JFlag#RETURN_NULL_ON_NULL
587     * @see JFlag#RETURN_DEFVAL_ON_NULL
588     * @see JFlag#RETURN_NULL_ON_ANY_ALL
589     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
590     */
591    protected static <T> T JNAEX(
592            JsonArray ja, int index, T defaultValue, int FLAGS, JsonValue.ValueType expectedType,
593            Class<T> returnClass
594        )
595    {
596        if ((FLAGS & RETURN_NULL_ON_NULL) != 0)         return null;
597        if ((FLAGS & RETURN_DEFVAL_ON_NULL) != 0)       return defaultValue;
598        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
599        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
600
601        throw new JsonNullArrException(ja, index, expectedType, returnClass);
602    }
603
604    /**
605     * Flag Checker for {@link JsonNullObjException}
606     * 
607     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
608     * and either returns the appropriate value accordingly, or throws
609     * {@code JsonNullObjException}.
610     * 
611     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
612     * 
613     * @param <T> If requested, the default-value is returned, and this is its type.
614     * 
615     * @return Can return either the user-provided default-value, or null depending on whether a
616     * match was found in the user's request settings ({@code 'FLAGS'}).
617     * 
618     * @throws JsonNullObjException If no flag was set specifying one of the two return-value
619     * options.
620     * 
621     * @see JFlag#RETURN_NULL_ON_NULL
622     * @see JFlag#RETURN_DEFVAL_ON_NULL
623     * @see JFlag#RETURN_NULL_ON_ANY_ALL
624     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
625     */
626    protected static <T> T JNOEX(
627            JsonObject jo, String propertyName, T defaultValue, int FLAGS,
628            JsonValue.ValueType expectedType, Class<T> returnClass
629        )
630    {
631        if ((FLAGS & RETURN_NULL_ON_NULL) != 0)         return null;
632        if ((FLAGS & RETURN_DEFVAL_ON_NULL) != 0)       return defaultValue;
633        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
634        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
635
636        throw new JsonNullObjException(jo, propertyName, expectedType, returnClass);
637    }
638
639    /**
640     * Flag Checker for {@link JsonTypeArrException}
641     * 
642     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
643     * and either returns the appropriate value accordingly, or throws
644     * {@code JsonTypeArrException}.
645     * 
646     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
647     * 
648     * @param <T> If requested, the default-value is returned, and this is its type.
649     * 
650     * @return Can return either the user-provided default-value, or null depending on whether a
651     * match was found in the user's request settings ({@code 'FLAGS'}).
652     * 
653     * @throws JsonTypeArrException If no flag was set specifying one of the two return-value
654     * options.
655     * 
656     * @see JFlag#RETURN_NULL_ON_WRONG_JSONTYPE
657     * @see JFlag#RETURN_DEFVAL_ON_WRONG_JSONTYPE
658     * @see JFlag#RETURN_NULL_ON_ANY_ALL
659     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
660     */
661    protected static <T> T JTAEX(
662            JsonArray ja, int index, T defaultValue, int FLAGS, JsonValue.ValueType expectedType,
663            JsonValue retrievedValue, Class<T> returnClass
664        )
665    {
666        if ((FLAGS & RETURN_NULL_ON_WRONG_JSONTYPE) != 0)   return null;
667        if ((FLAGS & RETURN_DEFVAL_ON_WRONG_JSONTYPE) != 0) return defaultValue;
668        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)          return null;
669        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)        return defaultValue;
670
671        throw new JsonTypeArrException(ja, index, expectedType, retrievedValue, returnClass);
672    }
673
674    /**
675     * Flag Checker for {@link JsonTypeObjException}
676     * 
677     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
678     * and either returns the appropriate value accordingly, or throws
679     * {@code JsonNullObjException}.
680     * 
681     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
682     * 
683     * @param <T> If requested, the default-value is returned, and this is its type.
684     * 
685     * @return Can return either the user-provided default-value, or null depending on whether a
686     * match was found in the user's request settings ({@code 'FLAGS'}).
687     * 
688     * @throws JsonNullObjException If no flag was set specifying one of the two return-value
689     * options.
690     * 
691     * @see JFlag#RETURN_NULL_ON_WRONG_JSONTYPE
692     * @see JFlag#RETURN_DEFVAL_ON_WRONG_JSONTYPE
693     * @see JFlag#RETURN_NULL_ON_ANY_ALL
694     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
695     */
696    protected static <T> T JTOEX(
697            JsonObject jo, String propertyName, T defaultValue, int FLAGS,
698            JsonValue.ValueType expectedType, JsonValue retrievedValue, Class<T> returnClass
699        )
700    {
701        if ((FLAGS & RETURN_NULL_ON_WRONG_JSONTYPE) != 0)   return null;
702        if ((FLAGS & RETURN_DEFVAL_ON_WRONG_JSONTYPE) != 0) return defaultValue;
703        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)          return null;
704        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)        return defaultValue;
705
706        throw new JsonTypeObjException
707            (jo, propertyName, expectedType, retrievedValue, returnClass);
708    }
709
710    /**
711     * Flag Checker for {@link JsonStrParseArrException}
712     * 
713     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
714     * and either returns the appropriate value accordingly, or throws
715     * {@code JsonStrParseArrException}.
716     * 
717     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
718     * 
719     * @param <T> If requested, the default-value is returned, and this is its type.
720     * 
721     * @return Can return either the user-provided default-value, or null depending on whether a
722     * match was found in the user's request settings ({@code 'FLAGS'}).
723     * 
724     * @throws JsonStrParseArrException If no flag was set specifying one of the two return-value
725     * options.
726     * 
727     * @see JFlag#RETURN_NULL_ON_SPEX
728     * @see JFlag#RETURN_DEFVAL_ON_SPEX
729     * @see JFlag#RETURN_NULL_ON_ANY_ALL
730     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
731     */
732    protected static <T> T JSPAEX(
733            Exception e, JsonArray ja, int index, T defaultValue, int FLAGS,
734            JsonValue retrievedValue, Class<T> returnClass
735        )
736    {
737        if ((FLAGS & RETURN_NULL_ON_SPEX) != 0)         return null;
738        if ((FLAGS & RETURN_DEFVAL_ON_SPEX) != 0)       return defaultValue;
739        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
740        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
741
742        throw new JsonStrParseArrException(e, ja, index, retrievedValue, returnClass);
743    }
744
745    /**
746     * Flag Checker for {@link JsonStrParseObjException}
747     * 
748     * <BR /><BR />Checks whether the relevant flags were set in the users {@code FLAGS} parameter,
749     * and either returns the appropriate value accordingly, or throws
750     * {@code JsonStrParseObjException}.
751     * 
752     * <EMBED CLASS='external-html' DATA-FILE-ID=FLAG_PRECEDENCE>
753     * 
754     * @param <T> If requested, the default-value is returned, and this is its type.
755     * 
756     * @return Can return either the user-provided default-value, or null depending on whether a
757     * match was found in the user's request settings ({@code 'FLAGS'}).
758     * 
759     * @throws JsonStrParseObjException If no flag was set specifying one of the two return-value
760     * options.
761     * 
762     * @see JFlag#RETURN_NULL_ON_SPEX
763     * @see JFlag#RETURN_DEFVAL_ON_SPEX
764     * @see JFlag#RETURN_NULL_ON_ANY_ALL
765     * @see JFlag#RETURN_DEFVAL_ON_ANY_ALL
766     */
767    protected static <T> T JSPOEX(
768            Exception e, JsonObject jo, String propertyName, T defaultValue, int FLAGS,
769            JsonValue retrievedValue, Class<T> returnClass
770        )
771    {
772        if ((FLAGS & RETURN_NULL_ON_SPEX) != 0)         return null;
773        if ((FLAGS & RETURN_DEFVAL_ON_SPEX) != 0)       return defaultValue;
774        if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
775        if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
776
777        throw new JsonStrParseObjException(e, jo, propertyName, retrievedValue, returnClass);
778    }
779
780
781    // ********************************************************************************************
782    // ********************************************************************************************
783    // GET: USES-FLAG METHODS
784    // ********************************************************************************************
785    // ********************************************************************************************
786
787
788    /**
789     * This is an internal helper method for retrieving an element from a {@link JsonArray},
790     * and converting it to a <B STYLE='color: red;'>Java Type</B>.
791     * <EMBED CLASS=defs DATA-TYPE=number DATA-JTYPE=JsonNumber>
792     * @param ja Any instance of {@link JsonArray}
793     * @param index The array index containing the element to retrieve.
794     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
795     * @param defaultValue This is the 'Default Value' returned by this method, if there are any
796     * problems converting or extracting the specified number, and the appropriate flags are set.
797     * 
798     * @return On success, this method returns the converted number.
799     * 
800     * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_IOOBEX>
801     * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JAEX>
802     * @throws JsonNullArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNAEX>
803     * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTAEX>
804     * 
805     * @see ReadJSON#getINTEGER(JsonArray, int, int, int)
806     * @see ReadJSON#getLONG(JsonArray, int, int, long)
807     * @see ReadJSON#getSHORT(JsonArray, int, int, short)
808     * @see ReadJSON#getBYTE(JsonArray, int, int, byte)
809     * @see ReadJSON#getDOUBLE(JsonArray, int, int, double)
810     * @see ReadJSON#getFLOAT(JsonArray, int, int, float)
811     * @see ReadJSON#getNUMBER(JsonArray, int, int, Number)
812     */
813    protected static <T extends java.lang.Number> T GET(
814            JsonArray ja, int index,
815            int FLAGS, T defaultValue,
816            Class<T> returnClass,
817            Function<JsonNumber, T> jsonTypeToJavaType,
818            Function<JsonNumber, T> typeToType2
819        )
820    {
821        // When TRUE, the index provided turned out to be outside of the bounds of the array.  The
822        // IndexOutOfBounds "handler" (the method called here) will check the FLAGS, and:
823        //
824        //  1) return the defaultValue (if Requested by 'FLAGS' for IOOBEX)
825        //  2) return null (if Requested by 'FLAGS' for IOOBEX)
826        //  3) throw IndexOutOfBoundsException
827        //
828        // NOTE: It is probably a "little less efficient" to turn this into a method call,
829        //       since there are all these parameters that have to be passed, but this is
830        //       trading "readability" (less head-aches) in exchange for efficiency.
831        //
832        // This point applies to all of the "Exception Flag Handlers" used here
833
834        if (index >= ja.size()) return IOOBEX(ja, index, defaultValue, FLAGS);
835
836        JsonValue jv = ja.get(index);
837
838        switch (jv.getValueType())
839        {
840            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullArrException 'handler'
841            // will do one of the following:
842            //
843            //  1) return the defaultValue (if Requested by 'FLAGS' for JNAEX)
844            //  2) return null (if Requested by 'FLAGS' for JNAEX)
845            //  3) throw JsonNullArrException
846
847            case NULL: return JNAEX(ja, index, defaultValue, FLAGS, NUMBER, returnClass);
848
849            case NUMBER:
850
851                // Temp Variable, Used Twice (Just a Cast)
852                JsonNumber n = (JsonNumber) jv;
853
854                try
855                    { return jsonTypeToJavaType.apply(n); }
856
857                // Because
858                //
859                // 1) A method for this code would only be invoked here, and...
860                // 2) And because there would be 9 parameters to pass, 
861                // 3) the 'inline' version of "Flag Handler" is left here!
862                //
863                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
864                //       are different for each of the 4 methods where they are used.
865
866                catch (ArithmeticException ae)
867                {
868                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
869                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
870                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)       return typeToType2.apply(n);
871                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
872                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
873            
874                    throw new JsonArithmeticArrException
875                        (ae, ja, index, NUMBER, jv, returnClass);
876                }
877
878            // The JsonValue at the specified array-index does not contain an JsonNumber.
879            // The "JsonTypeArrException Handler" will do one of these:
880            //
881            //  1) return the defaultValue (if Requested by 'FLAGS' for JTAEX)
882            //  2) return null (if Requested by 'FLAGS' for JTAEX)
883            //  3) throw JsonTypeArrException
884
885            default: return JTAEX(ja, index, defaultValue, FLAGS, NUMBER, jv, returnClass);
886        }
887    }
888
889    /**
890     * This is an internal helper method for retrieving a property from a {@link JsonObject},
891     * and converting it to a <B STYLE='color: red;'>Java Type</B>.
892     * <EMBED CLASS=defs DATA-TYPE=number DATA-JTYPE=JsonNumber>
893     * 
894     * @param jo Any instance of {@link JsonObject}
895     * @param propertyName The name of the property in {@code 'jo'} to retrieve.
896     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
897     * @param defaultValue This is the 'Default Value' returned by this method, if there are any
898     * problems converting or extracting the specified number, and the appropriate flags are set
899     * 
900     * @return On success, this method returns the converted number
901     * 
902     * @throws JsonPropMissingException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JPMEX>
903     * @throws JsonArithmeticObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JAEX>
904     * @throws JsonNullObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNOEX>
905     * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTOEX>
906     * 
907     * @see ReadJSON#getINTEGER(JsonObject, String, int, int)
908     * @see ReadJSON#getLONG(JsonObject, String, int, long)
909     * @see ReadJSON#getSHORT(JsonObject, String, int, short)
910     * @see ReadJSON#getBYTE(JsonObject, String, int, byte)
911     * @see ReadJSON#getDOUBLE(JsonObject, String, int, double)
912     * @see ReadJSON#getFLOAT(JsonObject, String, int, float)
913     * @see ReadJSON#getNUMBER(JsonObject, String, int, Number)
914     */
915    protected static <T extends java.lang.Number> T GET(
916            JsonObject jo, String propertyName,
917            int FLAGS, T defaultValue,
918            Class<T> returnClass,
919            Function<JsonNumber, T> jsonTypeToJavaType,
920            Function<JsonNumber, T> typeToType2
921        )
922    {
923        JsonValue jv = jo.get(propertyName);
924
925        // When TRUE, the user-specified 'property' (named by 'propertyName') isn't actually one
926        // of the listed properties inside the JsonObject.  The JsonPropMissingException "handler"
927        // (the method called here) will check the FLAGS, and:
928        //
929        //  1) return the defaultValue (if Requested by 'FLAGS' for JPMEX)
930        //  2) return null (if Requested by 'FLAGS' for JPMEX)
931        //  3) throw JsonPropMissingException
932        //
933        // NOTE: It is probably a "little less efficient" to turn this into a method call,
934        //       since there are all these parameters that have to be passed, but this is
935        //       trading "readability" (less head-aches) in exchange for efficiency.
936        //
937        // This point applies to all of the "Exception Flag Handlers" used here
938
939        if (jv == null) return JPMEX(jo, propertyName, defaultValue, FLAGS, NUMBER, returnClass);
940
941        switch (jv.getValueType())
942        {
943            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullObjException 'handler'
944            // will do one of the following:
945            //
946            //  1) return the defaultValue (if Requested by 'FLAGS' for JNOEX)
947            //  2) return null (if Requested by 'FLAGS' for JNOEX)
948            //  3) throw JsonNullArrException
949
950            case NULL: return JNOEX(jo, propertyName, defaultValue, FLAGS, NUMBER, returnClass);
951
952            case NUMBER:
953
954                // Temp Variable, Used Twice (Just a Cast)
955                JsonNumber n = (JsonNumber) jv;
956
957                try
958                    { return jsonTypeToJavaType.apply(n); }
959
960                // Because
961                //
962                // 1) A method for this code would only be invoked here, and...
963                // 2) And because there would be 9 parameters to pass, 
964                // 3) the 'inline' version of "Flag Handler" is left here!
965                //
966                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
967                //       are different for each of the 4 methods where they are used.
968
969                catch (ArithmeticException ae)
970                {
971                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
972                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
973                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)       return typeToType2.apply(n);
974                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
975                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
976
977                    throw new JsonArithmeticObjException
978                        (ae, jo, propertyName, NUMBER, jv, returnClass);
979                }
980
981            // The JsonValue of 'propertyName' does not contain an JsonNumber.
982            // The "JsonTypeObjException Handler" will do one of these:
983            //
984            //  1) return the defaultValue (if Requested by 'FLAGS' for JTOEX)
985            //  2) return null (if Requested by 'FLAGS' for JTOEX)
986            //  3) throw JsonTypeObjException
987
988            default: return JTOEX(jo, propertyName, defaultValue, FLAGS, NUMBER, jv, returnClass);
989        }
990    }
991
992
993    // ********************************************************************************************
994    // ********************************************************************************************
995    // HELPER PARSE - JsonString Inputs (also uses flags)
996    // ********************************************************************************************
997    // ********************************************************************************************
998
999
1000    /**
1001     * Retrieve a {@link JsonArray} element containing a {@link JsonString}, and transform it to
1002     * a <B STYLE='color: red'>Java Type</B>, with either a user-provided parser, or the standard
1003     * java parser for that class (passed as a parameter).
1004     * 
1005     * @param <T> The type of the returned value
1006     * @param ja Any instance of {@link JsonArray}
1007     * @param index array-index containing the {@link JsonString} to retrieve.
1008     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
1009     * @param defaultValue User-provided default-value, only returned if flags are set.
1010     * @param parser A valid {@code String -> 'T'} parser.  This parameter may be null.
1011     * @param defaultParser1 Default {@code String -> 'T'} parser.
1012     * @param defaultParser2 {@code String -> 'T'} parser, that will round on Arithmetic Exceptions
1013     * 
1014     * @return On success, this method returns the converted type.
1015     * 
1016     * @throws JsonPropMissingException {@code 'jo'} doesn't have {@code 'propertyName'}, unless
1017     * flags are set.
1018     * @throws JsonArithmeticArrException after parse, conversion fails, and flags aren't set
1019     * @throws JsonStrParseArrException parser-failure unless flags are set
1020     * @throws JsonNullArrException property contains null, unless flags are set
1021     * @throws JsonTypeArrException property doesn't contain {@code JsonString}, unless flags are
1022     * set.
1023     * 
1024     * @see ReadJSON#parseINTEGER(JsonArray, int, int, int, Function)
1025     * @see ReadJSON#parseLONG(JsonArray, int, int, long, Function)
1026     * @see ReadJSON#parseSHORT(JsonArray, int, int, short, Function)
1027     * @see ReadJSON#parseBYTE(JsonArray, int, int, byte, Function)
1028     * @see ReadJSON#parseDOUBLE(JsonArray, int, int, double, Function)
1029     * @see ReadJSON#parseFLOAT(JsonArray, int, int, float, Function)
1030     * @see ReadJSON#parseNUMBER(JsonArray, int, int, Number, Function)
1031     */
1032    protected static <T extends Number> T PARSE(
1033            JsonArray ja, int index, int FLAGS, T defaultValue, Class<T> returnClass,
1034            Function<String, T> parser,
1035            Function<BigDecimal, T> defaultParser1,
1036            Function<BigDecimal, T> defaultParser2
1037        )
1038    {
1039        // When TRUE, the index provided turned out to be outside of the bounds of the array.  The
1040        // IndexOutOfBounds "handler" (the method called here) will check the FLAGS, and:
1041        //
1042        //  1) return the defaultValue (if Requested by 'FLAGS' for IOOBEX)
1043        //  2) return null (if Requested by 'FLAGS' for IOOBEX)
1044        //  3) throw IndexOutOfBoundsException
1045        //
1046        // NOTE: It is probably a "little less efficient" to turn this into a method call,
1047        //       since there are all these parameters that have to be passed, but this is
1048        //       trading "readability" (less head-aches) in exchange for efficiency.
1049        //
1050        // This point applies to all of the "Exception Flag Handlers" used here
1051
1052        if (index >= ja.size()) return IOOBEX(ja, index, defaultValue, FLAGS);
1053
1054        JsonValue jv = ja.get(index);
1055
1056        switch (jv.getValueType())
1057        {
1058            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullArrException 'handler'
1059            // will do one of the following:
1060            //
1061            //  1) return the defaultValue (if Requested by 'FLAGS' for JNAEX)
1062            //  2) return null (if Requested by 'FLAGS' for JNAEX)
1063            //  3) throw JsonNullArrException
1064
1065            case NULL: return JNAEX(ja, index, defaultValue, FLAGS, STRING, returnClass);
1066
1067            case STRING:
1068
1069                String s = ((JsonString) jv).getString();
1070
1071                // NOTE: This isn't actually an "Exception Case", and if the user hasn't made
1072                //       a request, the empty-string is passed to whatever parser is configured
1073
1074                if (s.length() == 0)
1075                {
1076                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
1077                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
1078                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
1079                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
1080                }
1081
1082                // Temp Variable, used in order not to invoke the BigDecimal contructor twice
1083                BigDecimal bd = null;
1084
1085                try
1086                {
1087                    return (parser != null)
1088                        ? parser.apply(s)
1089                        : defaultParser1.apply(bd = new BigDecimal(s.trim()));
1090
1091                        // NOTE: 'bd' will not be null if "ArithmeticException" is thrown...
1092                        // new BigDecimal throws "NumberFormatException" is thrown
1093                        // parser.applly can throw ArithmeticException
1094                }
1095
1096                // Because
1097                //
1098                // 1) A method for this code would only be invoked here, and...
1099                // 2) And because there would be 9 parameters to pass, 
1100                // 3) the 'inline' version of "Flag Handler" is left here!
1101                //
1102                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
1103                //       are different for each of the 4 methods where they are used.
1104
1105                catch (ArithmeticException ae)
1106                {
1107                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
1108                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
1109                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)       return defaultParser2.apply(bd);
1110                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
1111                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
1112
1113                    throw new JsonArithmeticArrException(ae, ja, index, STRING, jv, returnClass);
1114                }
1115
1116                // HANDLER STRIKES AGAIN! - but this time for "JsonStrParseArrException"
1117                // RETURNS: null, or defaultValue, (otherwise throws JsonStrParseArrException)
1118
1119                catch (Exception e)
1120                    { return JSPAEX(e, ja, index, defaultValue, FLAGS, jv, returnClass); }
1121
1122            // The JsonValue at the specified array-index does not contain an JsonString.
1123            // The "JsonTypeArrException Handler" will do one of these:
1124            //
1125            //  1) return the defaultValue (if Requested by 'FLAGS' for JTAEX)
1126            //  2) return null (if Requested by 'FLAGS' for JTAEX)
1127            //  3) throw JsonTypeArrException
1128
1129            default: return JTAEX(ja, index, defaultValue, FLAGS, STRING, jv, returnClass);
1130        }
1131    }
1132
1133    /**
1134     * Retrieve a {@link JsonObject} property containing a {@link JsonString}, and transform it to
1135     * a <B STYLE='color: red'>Java Type</B>, with either a user-provided parser, or the standard
1136     * java parser for that class (passed as a parameter).
1137     * 
1138     * @param <T> The type of the returned value.
1139     * @param jo Any instance of {@link JsonObject}
1140     * @param propertyName propertyName containing the {@link JsonString} to retrieve.
1141     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
1142     * @param defaultValue User-provided default-value, only returned if flags are set.
1143     * @param parser A valid {@code String -> 'T'} parser.  This parameter may be null.
1144     * @param defaultParser1 Default {@code String -> 'T'} parser.
1145     * @param defaultParser2 {@code String -> 'T'} parser, that will round on Arithmetic Exceptions
1146     * 
1147     * @return On success, this method returns the converted type instance.
1148     * 
1149     * @throws JsonPropMissingException {@code 'jo'} doesn't have {@code 'propertyName'}, unless
1150     * flags are set.
1151     * @throws JsonArithmeticObjException after parse, conversion fails, and flags aren't set
1152     * @throws JsonStrParseObjException parser-failure unless flags are set
1153     * @throws JsonNullObjException property contains null, unless flags are set
1154     * @throws JsonTypeObjException property doesn't contain {@code JsonString}, unless flags are
1155     * set.
1156     * 
1157     * @see ReadJSON#parseINTEGER(JsonObject, String, int, int, Function)
1158     * @see ReadJSON#parseLONG(JsonObject, String, int, long, Function)
1159     * @see ReadJSON#parseSHORT(JsonObject, String, int, short, Function)
1160     * @see ReadJSON#parseBYTE(JsonObject, String, int, byte, Function)
1161     * @see ReadJSON#parseDOUBLE(JsonObject, String, int, double, Function)
1162     * @see ReadJSON#parseFLOAT(JsonObject, String, int, float, Function)
1163     * @see ReadJSON#parseNUMBER(JsonObject, String, int, Number, Function)
1164     */
1165    protected static <T extends Number> T PARSE(
1166            JsonObject jo, String propertyName, int FLAGS, T defaultValue, Class<T> returnClass,
1167            Function<String, T> parser,
1168            Function<BigDecimal, T> defaultParser1,
1169            Function<BigDecimal, T> defaultParser2
1170        )
1171    {
1172        JsonValue jv = jo.get(propertyName);
1173
1174        // When TRUE, the user-specified 'property' (named by 'propertyName') isn't actually one
1175        // of the listed properties inside the JsonObject.  The JsonPropMissingException "handler"
1176        // (the method called here) will check the FLAGS, and:
1177        //
1178        //  1) return the defaultValue (if Requested by 'FLAGS' for JPMEX)
1179        //  2) return null (if Requested by 'FLAGS' for JPMEX)
1180        //  3) throw JsonPropMissingException
1181        //
1182        // NOTE: It is probably a "little less efficient" to turn this into a method call,
1183        //       since there are all these parameters that have to be passed, but this is
1184        //       trading "readability" (less head-aches) in exchange for efficiency.
1185        //
1186        // This point applies to all of the "Exception Flag Handlers" used here
1187
1188        if (jv == null) return JPMEX(jo, propertyName, defaultValue, FLAGS, STRING, returnClass);
1189
1190        switch (jv.getValueType())
1191        {
1192            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullObjException 'handler'
1193            // will do one of the following:
1194            //
1195            //  1) return the defaultValue (if Requested by 'FLAGS' for JNOEX)
1196            //  2) return null (if Requested by 'FLAGS' for JNOEX)
1197            //  3) throw JsonNullArrException
1198
1199            case NULL: return JNOEX(jo, propertyName, defaultValue, FLAGS, STRING, returnClass);
1200
1201            case STRING:
1202
1203                String s = ((JsonString) jv).getString();
1204
1205                // NOTE: This isn't actually an "Exception Case", and if the user hasn't made
1206                //       a request, the empty-string is passed to whatever parser is configured
1207
1208                if (s.length() == 0)
1209                {
1210                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
1211                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
1212                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
1213                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
1214                }
1215
1216                // Temp Variable, used in order not to invoke the BigDecimal contructor twice
1217                BigDecimal bd = null;
1218
1219                try
1220                {
1221                    return (parser != null)
1222                        ? parser.apply(s)
1223                        : defaultParser1.apply(bd = new BigDecimal(s.trim()));
1224
1225                        // NOTE: 'bd' will not be null if "ArithmeticException" is thrown...
1226                        // new BigDecimal throws "NumberFormatException" is thrown
1227                        // parser.applly can throw ArithmeticException
1228                }
1229
1230                // Because
1231                //
1232                // 1) A method for this code would only be invoked here, and...
1233                // 2) And because there would be 9 parameters to pass, 
1234                // 3) the 'inline' version of "Flag Handler" is left here!
1235                //
1236                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
1237                //       are different for each of the 4 methods where they are used.
1238
1239                catch (ArithmeticException ae)
1240                {
1241                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
1242                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
1243                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)      return defaultParser2.apply(bd);
1244                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
1245                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
1246
1247                    throw new JsonArithmeticObjException
1248                        (ae, jo, propertyName, STRING, jv, returnClass);
1249                }
1250
1251                // HANDLER STRIKES AGAIN! - but this time for "JsonStrParseObjException"
1252                // RETURNS: null, or defaultValue, (otherwise throws JsonStrParseObjException)
1253
1254                catch (Exception e)
1255                    { return JSPOEX(e, jo, propertyName, defaultValue, FLAGS, jv, returnClass); }
1256
1257            // The JsonValue of 'propertyName' does not contain an JsonString.
1258            // The "JsonTypeObjException Handler" will do one of these:
1259            //
1260            //  1) return the defaultValue (if Requested by 'FLAGS' for JTOEX)
1261            //  2) return null (if Requested by 'FLAGS' for JTOEX)
1262            //  3) throw JsonTypeObjException
1263
1264            default: return JTOEX(jo, propertyName, defaultValue, FLAGS, STRING, jv, returnClass);
1265        }
1266    }
1267}