001package Torello.JSON;
002
003import Torello.JavaDoc.Annotations.IntoHTMLTable;
004import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.BlueDither;
005import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.GreenDither;
006
007import static Torello.JSON.JFlag.*;
008import static Torello.JSON.RJInternal.*;
009import static javax.json.JsonValue.ValueType.*;
010
011import javax.json.JsonObject;
012import javax.json.JsonArray;
013import javax.json.JsonString;
014import javax.json.JsonNumber;
015import javax.json.JsonValue;
016
017import java.math.BigDecimal;
018import java.util.function.Function;
019
020/**
021 * Builds on the J2EE Standard Release JSON Parsing Tools by providing additional
022 * help with converting JSON Data into <B STYLE='color: red'>Java Boxed-Primitive Types</B>
023 * 
024 * <EMBED CLASS='external-html' DATA-FILE-ID=ALL_CLASSES_NOTE>
025 * <EMBED CLASS='external-html' DATA-FILE-ID=PARSE_BOXED_JSON>
026 * <EMBED CLASS='external-html' DATA-FILE-ID=PARSE_BOXED_PTABLE>
027 * <EMBED CLASS='external-html' DATA-CH='java.lang.Character' DATA-FILE-ID=JAVA_LANG_CHAR>
028 * 
029 * @see JsonObject
030 * @see JsonArray
031 */
032@Torello.JavaDoc.Annotations.StaticFunctional
033public class ParseBoxedJSON
034{
035    private ParseBoxedJSON() { }
036
037
038    // ********************************************************************************************
039    // ********************************************************************************************
040    // Parse from a JsonArray, into a Boxed-Primitive.  ACCEPT USER ERROR-CONTROl FLAGS
041    // ********************************************************************************************
042    // ********************************************************************************************
043
044
045    /**
046     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JA>
047     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
048     */
049    @IntoHTMLTable(
050        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Integer",
051        background=BlueDither
052    )
053    public static Integer parseInteger(
054            final JsonArray                 ja,
055            final int                       index,
056            final int                       FLAGS,
057            final int                       defaultValue,
058            final Function<String, Integer> optionalParser
059        )
060    {
061        return PARSE(
062            ja, index, FLAGS, defaultValue, Integer.class, optionalParser,
063            BigDecimal::intValueExact, BigDecimal::intValue
064        );
065    }
066
067    /**
068     * <EMBED CLASS='external-html' DATA-TYPE=Long DATA-FILE-ID=PARSE_BOXED_WF_JA>
069     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
070     */
071    @IntoHTMLTable(
072        title=  "Retrieve a JsonString from a JsonArray index, and parse to a Boxed Long " +
073                "Integer",
074        background=GreenDither
075    )
076    public static Long parseLong(
077            final JsonArray                 ja,
078            final int                       index,
079            final int                       FLAGS,
080            final long                      defaultValue,
081            final Function<String, Long>    optionalParser
082        )
083    {
084        return PARSE(
085            ja, index, FLAGS, defaultValue, Long.class, optionalParser,
086            BigDecimal::longValueExact, BigDecimal::longValue
087        );
088    }
089
090    /**
091     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JA>
092     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
093     */
094    @IntoHTMLTable(
095        title=  "Retrieve a JsonString from a JsonArray index, and parse to a Boxed Short " +
096                "Integer",
097        background=BlueDither
098    )
099    public static Short parseShort(
100            final JsonArray                 ja,
101            final int                       index,
102            final int                       FLAGS,
103            final short                     defaultValue,
104            final Function<String, Short>   optionalParser
105        )
106    {
107        return PARSE(
108            ja, index, FLAGS, defaultValue, Short.class, optionalParser,
109            BigDecimal::shortValueExact, BigDecimal::shortValue
110        );
111    }
112
113    /**
114     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JA>
115     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
116     */
117    @IntoHTMLTable(
118        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Byte",
119        background=GreenDither
120    )
121    public static Byte parseByte(
122            final JsonArray         ja,
123            final int               index,
124            final int               FLAGS,
125            final byte              defaultValue,
126            Function<String, Byte>  optionalParser
127        )
128    {
129        return PARSE(
130            ja, index, FLAGS, defaultValue, Byte.class, optionalParser,
131            BigDecimal::byteValueExact, BigDecimal::byteValue
132        );
133    }
134
135    /**
136     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JA>
137     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
138     */
139    @IntoHTMLTable(
140        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Double",
141        background=BlueDither
142    )
143    public static Double parseDouble(
144            final JsonArray                 ja,
145            final int                       index,
146            final int                       FLAGS,
147            final double                    defaultValue,
148            final Function<String, Double>  optionalParser
149        )
150    {
151        return PARSE(
152            ja, index, FLAGS, defaultValue, Double.class, optionalParser,
153            RJInternal::DOUBLE_WITH_CHECK, BigDecimal::doubleValue
154        );
155    }
156
157    /**
158     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JA>
159     * @see #PARSE(JsonArray, int, int, Number, Class, Function, Function, Function)
160     */
161    @IntoHTMLTable(
162        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Float",
163        background=GreenDither
164    )
165    public static Float parseFloat(
166            final JsonArray                 ja,
167            final int                       index,
168            final int                       FLAGS,
169            final float                     defaultValue,
170            final Function<String, Float>   optionalParser
171        )
172    {
173        return PARSE(
174            ja, index, FLAGS, defaultValue, Float.class, optionalParser,
175            RJInternal::FLOAT_WITH_CHECK, BigDecimal::floatValue
176        );
177    }
178
179
180    // ********************************************************************************************
181    // ********************************************************************************************
182    // Parse from a JsonObject, into a Boxed-Primitive.  ACCEPT USER ERROR-CONTROl FLAGS
183    // ********************************************************************************************
184    // ********************************************************************************************
185
186
187    /**
188     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_WF_JO>
189     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
190     */
191    @IntoHTMLTable(
192        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Integer",
193        background=BlueDither
194    )
195    public static Integer parseInteger(
196            final JsonObject                jo,
197            final String                    propertyName,
198            final int                       FLAGS,
199            final int                       defaultValue,
200            final Function<String, Integer> optionalParser
201        )
202    {
203        return PARSE(
204            jo, propertyName, FLAGS, defaultValue, Integer.class, optionalParser,
205            BigDecimal::intValueExact, BigDecimal::intValue
206        );
207    }
208
209    /**
210     * <EMBED CLASS='external-html' DATA-TYPE=Long DATA-FILE-ID=PARSE_BOXED_WF_JO>
211     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
212     */
213    @IntoHTMLTable(
214        title=  "Retrieve a JsonString from a JsonObject property, and parse to a Boxed Long " +
215                "Integer",
216        background=GreenDither
217    )
218    public static Long parseLong(
219            final JsonObject                jo,
220            final String                    propertyName,
221            final int                       FLAGS,
222            final long                      defaultValue,
223            final Function<String, Long>    optionalParser
224        )
225    {
226        return PARSE(
227            jo, propertyName, FLAGS, defaultValue, Long.class, optionalParser,
228            BigDecimal::longValueExact, BigDecimal::longValue
229        );
230    }
231
232    /**
233     * <EMBED CLASS='external-html' DATA-TYPE=Short DATA-FILE-ID=PARSE_BOXED_WF_JO>
234     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
235     */
236    @IntoHTMLTable(
237        title=  "Retrieve a JsonString from a JsonObject property, and parse to a Boxed Short " +
238                "Integer",
239        background=BlueDither
240    )
241    public static Short parseShort(
242            final JsonObject                jo,
243            final String                    propertyName,
244            final int                       FLAGS,
245            final short                     defaultValue,
246            final Function<String, Short>   optionalParser
247        )
248    {
249        return PARSE(
250            jo, propertyName, FLAGS, defaultValue, Short.class, optionalParser,
251            BigDecimal::shortValueExact, BigDecimal::shortValue
252        );
253    }
254
255    /**
256     * <EMBED CLASS='external-html' DATA-TYPE=Byte DATA-FILE-ID=PARSE_BOXED_WF_JO>
257     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
258     */
259    @IntoHTMLTable(
260        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Byte",
261        background=GreenDither
262    )
263    public static Byte parseByte(
264            final JsonObject                jo,
265            final String                    propertyName,
266            final int                       FLAGS,
267            final byte                      defaultValue,
268            final Function<String, Byte>    optionalParser
269        )
270    {
271        return PARSE(
272            jo, propertyName, FLAGS, defaultValue, Byte.class, optionalParser,
273            BigDecimal::byteValueExact, BigDecimal::byteValue
274        );
275    }
276
277    /**
278     * <EMBED CLASS='external-html' DATA-TYPE=Double DATA-FILE-ID=PARSE_BOXED_WF_JO>
279     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
280     */
281    @IntoHTMLTable(
282        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Double",
283        background=BlueDither
284    )
285    public static Double parseDouble(
286            final JsonObject                jo,
287            final String                    propertyName,
288            final int                       FLAGS,
289            final double                    defaultValue,
290            final Function<String, Double>  optionalParser
291        )
292    {
293        return PARSE(
294            jo, propertyName, FLAGS, defaultValue, Double.class, optionalParser,
295            RJInternal::DOUBLE_WITH_CHECK, BigDecimal::doubleValue
296        );
297    }
298
299    /**
300     * <EMBED CLASS='external-html' DATA-TYPE=Float DATA-FILE-ID=PARSE_BOXED_WF_JO>
301     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
302     */
303    @IntoHTMLTable(
304        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Float",
305        background=GreenDither
306    )
307    public static Float parseFloat(
308            final JsonObject                jo,
309            final String                    propertyName,
310            final int                       FLAGS,
311            final float                     defaultValue,
312            final Function<String, Float>   optionalParser
313        )
314    {
315        return PARSE(
316            jo, propertyName, FLAGS, defaultValue, Float.class, optionalParser,
317            RJInternal::FLOAT_WITH_CHECK, BigDecimal::floatValue
318        );
319    }
320
321
322    // ********************************************************************************************
323    // ********************************************************************************************
324    // Parse from a JsonArray, into a Boxed-Primitive.  NO FLAGS, ALWAYS THROW ON ERROR
325    // ********************************************************************************************
326    // ********************************************************************************************
327
328
329    /**
330     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_NF_JA>
331     * @see #PARSE(JsonObject, String, int, Number, Class, Function, Function, Function)
332     */
333    @IntoHTMLTable(
334        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Integer",
335        background=BlueDither
336    )
337    public static Integer parseInteger(final JsonArray ja, final int index)
338    { return PARSE_NO_FLAGS(ja, index, Integer.class, Integer::parseInt); }
339
340    /**
341     * <EMBED CLASS='external-html' DATA-TYPE=Long DATA-FILE-ID=PARSE_BOXED_NF_JA>
342     * @see #PARSE_NO_FLAGS(JsonArray, int, Class, Function)
343     */
344    @IntoHTMLTable(
345        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed Long Integer",
346        background=GreenDither
347    )
348    public static Long parseLong(final JsonArray ja, final int index)
349    { return PARSE_NO_FLAGS(ja, index, Long.class, Long::parseLong); }
350
351    /**
352     * <EMBED CLASS='external-html' DATA-TYPE=Short DATA-FILE-ID=PARSE_BOXED_NF_JA>
353     * @see #PARSE_NO_FLAGS(JsonArray, int, Class, Function)
354     */
355    @IntoHTMLTable(
356        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed Short Integer",
357        background=BlueDither
358    )
359    public static Short parseShort(final JsonArray ja, final int index)
360    { return PARSE_NO_FLAGS(ja, index, Short.class, Short::parseShort); }
361
362    /**
363     * <EMBED CLASS='external-html' DATA-TYPE=Byte DATA-FILE-ID=PARSE_BOXED_NF_JA>
364     * @see #PARSE_NO_FLAGS(JsonArray, int, Class, Function)
365     */
366    @IntoHTMLTable(
367        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Byte",
368        background=GreenDither
369    )
370    public static Byte parseByte(final JsonArray ja, final int index)
371    { return PARSE_NO_FLAGS(ja, index, Byte.class, Byte::parseByte); }
372
373    /**
374     * <EMBED CLASS='external-html' DATA-TYPE=Double DATA-FILE-ID=PARSE_BOXED_NF_JA>
375     * @see #PARSE_NO_FLAGS(JsonArray, int, Class, Function)
376     */
377    @IntoHTMLTable(
378        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Double",
379        background=BlueDither
380    )
381    public static Double parseDouble(final JsonArray ja, final int index)
382    { return PARSE_NO_FLAGS(ja, index, Double.class, Double::parseDouble); }
383
384    /**
385     * <EMBED CLASS='external-html' DATA-TYPE=Float DATA-FILE-ID=PARSE_BOXED_NF_JA>
386     * @see #PARSE_NO_FLAGS(JsonArray, int, Class, Function)
387     */
388    @IntoHTMLTable(
389        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Float",
390        background=GreenDither
391    )
392    public static Float parseFloat(final JsonArray ja, final int index)
393    { return PARSE_NO_FLAGS(ja, index, Float.class, Float::parseFloat); }
394
395
396    // ********************************************************************************************
397    // ********************************************************************************************
398    // Parse from a JsonObject, into a Boxed-Primitive.  NO FLAGS, ALWAYS THROW ON ERROR
399    // ********************************************************************************************
400    // ********************************************************************************************
401
402
403    /**
404     * <EMBED CLASS='external-html' DATA-TYPE=Integer DATA-FILE-ID=PARSE_BOXED_NF_JO>
405     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
406     */
407    @IntoHTMLTable(
408        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Integer",
409        background=BlueDither
410    )
411    public static Integer parseInteger
412        (final JsonObject jo, final String propertyName, final boolean isOptional)
413    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Integer.class, Integer::parseInt); }
414
415    /**
416     * <EMBED CLASS='external-html' DATA-TYPE=Long DATA-FILE-ID=PARSE_BOXED_NF_JO>
417     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
418     */
419    @IntoHTMLTable(
420        title=  "Retrieve a JsonString from a JsonObject property, and parse to a Boxed Long " +
421                "Integer",
422        background=GreenDither
423    )
424    public static Long parseLong
425        (final JsonObject jo, final String propertyName, final boolean isOptional)
426    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Long.class, Long::parseLong); }
427
428    /**
429     * <EMBED CLASS='external-html' DATA-TYPE=Short DATA-FILE-ID=PARSE_BOXED_NF_JO>
430     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
431     */
432    @IntoHTMLTable(
433        title=  "Retrieve a JsonString from a JsonObject property, and parse to a Boxed Short " +
434                "Integer",
435        background=BlueDither
436    )
437    public static Short parseShort
438        (final JsonObject jo, final String propertyName, final boolean isOptional)
439    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Short.class, Short::parseShort); }
440
441    /**
442     * <EMBED CLASS='external-html' DATA-TYPE=Byte DATA-FILE-ID=PARSE_BOXED_NF_JO>
443     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
444     */
445    @IntoHTMLTable(
446        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Byte",
447        background=GreenDither
448    )
449    public static Byte parseByte
450        (final JsonObject jo, final String propertyName, final boolean isOptional)
451    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Byte.class, Byte::parseByte); }
452
453    /**
454     * <EMBED CLASS='external-html' DATA-TYPE=Double DATA-FILE-ID=PARSE_BOXED_NF_JO>
455     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
456     */
457    @IntoHTMLTable(
458        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Double",
459        background=BlueDither
460    )
461    public static Double parseDouble
462        (final JsonObject jo, final String propertyName, final boolean isOptional)
463    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Double.class, Double::parseDouble); }
464
465    /**
466     * <EMBED CLASS='external-html' DATA-TYPE=Float DATA-FILE-ID=PARSE_BOXED_NF_JO>
467     * @see #PARSE_NO_FLAGS(JsonObject, String, boolean, Class, Function)
468     */
469    @IntoHTMLTable(
470        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Float",
471        background=GreenDither
472    )
473    public static Float parseFloat
474        (final JsonObject jo, final String propertyName, final boolean isOptional)
475    { return PARSE_NO_FLAGS(jo, propertyName, isOptional, Float.class, Float::parseFloat); }
476
477
478    // ********************************************************************************************
479    // ********************************************************************************************
480    // Boxed Boolean - ACCEPT USER ERROR-CONTROl FLAGS 
481    // ********************************************************************************************
482    // ********************************************************************************************
483
484
485    /** <EMBED CLASS='external-html' DATA-TYPE=Boolean DATA-FILE-ID=PARSE_BOXED_WF_JA> */
486    @IntoHTMLTable(
487        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Boolean",
488        background=BlueDither
489    )
490    public static Boolean parseBoolean(
491            final JsonArray                 ja,
492            final int                       index,
493            final int                       FLAGS,
494            final boolean                   defaultValue,
495            final Function<String, Boolean> optionalParser
496        )
497    {
498        if (index >= ja.size()) return IOOBEX(ja, index, defaultValue, FLAGS);
499
500        final JsonValue jv = ja.get(index);
501
502        switch (jv.getValueType())
503        {
504            case NULL: return JNAEX(ja, index, defaultValue, FLAGS, STRING, Boolean.class);
505
506            case STRING:
507
508                final String s = ((JsonString) jv).getString();
509
510                if (s.length() == 0)
511                {
512                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
513                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
514                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
515                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
516                }
517
518                try
519                {
520                    return (optionalParser != null)
521                        ? optionalParser.apply(s)
522                        : Boolean.parseBoolean(s.trim());
523                }
524
525                catch (Exception e)
526                    { return JSPAEX(e, ja, index, defaultValue, FLAGS, jv, Boolean.class); }
527
528            default: return JTAEX(ja, index, defaultValue, FLAGS, STRING, jv, Boolean.class);
529        }
530    }
531
532    /** <EMBED CLASS='external-html' DATA-TYPE=Boolean DATA-FILE-ID=PARSE_BOXED_WF_JO> */
533    @IntoHTMLTable(
534        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Integer",
535        background=GreenDither
536    )
537    public static Boolean parseBoolean(
538            final JsonObject                jo,
539            final String                    propertyName,
540            final int                       FLAGS,
541            final boolean                   defaultValue,
542            final Function<String, Boolean> optionalParser
543        )
544    {
545
546        final JsonValue jv = jo.get(propertyName);
547
548        if (jv == null) return JPMEX(jo, propertyName, defaultValue, FLAGS, STRING, Boolean.class);
549
550        switch (jv.getValueType())
551        {
552            case NULL: return JNOEX(jo, propertyName, defaultValue, FLAGS, STRING, Boolean.class);
553
554            case STRING:
555
556                final String s = ((JsonString) jv).getString();
557
558                if (s.length() == 0)
559                {
560                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
561                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
562                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
563                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
564                }
565
566                try
567                {
568                    return (optionalParser != null)
569                        ? optionalParser.apply(s)
570                        : Boolean.parseBoolean(s.trim());
571                }
572
573                catch (Exception e)
574                    { return JSPOEX(e, jo, propertyName, defaultValue, FLAGS, jv, Boolean.class); }
575
576            default: return JTOEX(jo, propertyName, defaultValue, FLAGS, STRING, jv, Boolean.class);
577        }
578    }
579
580
581    // ********************************************************************************************
582    // ********************************************************************************************
583    // Boolean - NO FLAGS, ALWAYS THROW ON ERROR
584    // ********************************************************************************************
585    // ********************************************************************************************
586
587
588    /** <EMBED CLASS='external-html' DATA-TYPE=Boolean DATA-FILE-ID=PARSE_BOXED_NF_JA> */
589    @IntoHTMLTable(
590        title="Retrieve a JsonString from a JsonArray index, and parse to a Boxed-Boolean",
591        background=BlueDither
592    )
593    public static Boolean parseBoolean(final JsonArray ja, final int i)
594    {
595        // Throws an IndexOutOfBoundsException
596        final JsonValue jv = ja.get(i);
597
598        switch (jv.getValueType())
599        {
600            case NULL: return null;
601
602            case STRING:
603
604                try
605                    { return Boolean.parseBoolean(((JsonString) jv).getString()); }
606
607                catch (Exception e)
608                    { throw new JsonStrParseArrException (e, ja, i, jv, Boolean.class); }
609
610            default: throw new JsonTypeArrException(ja, i, STRING, jv, Boolean.class);
611        }
612    }
613
614    /** <EMBED CLASS='external-html' DATA-TYPE=Boolean DATA-FILE-ID=PARSE_BOXED_NF_JO> */
615    @IntoHTMLTable(
616        title="Retrieve a JsonString from a JsonObject property, and parse to a Boxed-Integer",
617        background=GreenDither
618    )
619    public static Boolean parseBoolean
620        (final JsonObject jo, final String propertyName, final boolean isOptional)
621    {
622        final JsonValue jv = jo.get(propertyName);
623
624        if (jv == null)
625        {
626            if (isOptional) return null;
627            else            throw new JsonPropMissingException(jo, propertyName, STRING, Boolean.class);
628        }
629
630        switch (jv.getValueType())
631        {
632            case NULL: return null;
633
634            case STRING:
635
636                try
637                    { return Boolean.parseBoolean(((JsonString) jv).getString()); }
638
639                catch (Exception e)
640                    { throw new JsonStrParseObjException(e, jo, propertyName, jv, Boolean.class); }
641
642            default: throw new JsonTypeObjException(jo, propertyName, STRING, jv, Boolean.class);
643        }
644    }
645
646
647    // ********************************************************************************************
648    // ********************************************************************************************
649    // HELPER PARSE - JsonString Inputs (USES FLAGS)
650    // ********************************************************************************************
651    // ********************************************************************************************
652
653
654    /**
655     * Retrieve a {@link JsonArray} element containing a {@link JsonString}, and transform it to
656     * a <B STYLE='color: red'>Java Type</B>, with either a user-provided parser, or the standard
657     * java parser for that class (passed as a parameter).
658     * 
659     * @param <T> The type of the returned value
660     * @param ja Any instance of {@link JsonArray}
661     * @param index array-index containing the {@link JsonString} to retrieve.
662     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
663     * @param defaultValue User-provided default-value, only returned if flags are set.
664     * @param optionalParser A valid {@code String -> 'T'} parser.  This parameter may be null.
665     * @param defaultParser1 Default {@code String -> 'T'} parser.
666     * @param defaultParser2 {@code String -> 'T'} parser, that will round on Arithmetic Exceptions
667     * 
668     * @return On success, this method returns the converted type.
669     * 
670     * @throws JsonPropMissingException {@code 'jo'} doesn't have {@code 'propertyName'}, unless
671     * flags are set.
672     * @throws JsonArithmeticArrException after parse, conversion fails, and flags aren't set
673     * @throws JsonStrParseArrException parser-failure unless flags are set
674     * @throws JsonNullArrException property contains null, unless flags are set
675     * @throws JsonTypeArrException property doesn't contain {@code JsonString}, unless flags are
676     * set.
677     * 
678     * @see #parseInteger(JsonArray, int, int, int, Function)
679     * @see #parseLong(JsonArray, int, int, long, Function)
680     * @see #parseShort(JsonArray, int, int, short, Function)
681     * @see #parseByte(JsonArray, int, int, byte, Function)
682     * @see #parseDouble(JsonArray, int, int, double, Function)
683     * @see #parseFloat(JsonArray, int, int, float, Function)
684     * 
685     * @see ReadNumberJSON#parse(JsonArray, int, int, Number, Function)
686     * 
687     * @see RJInternal#IOOBEX(JsonArray, int, Object, int)
688     * @see RJInternal#JNAEX(JsonArray, int, Object, int, JsonValue.ValueType, Class)
689     * @see RJInternal#JSPAEX(Exception, JsonArray, int, Object, int, JsonValue, Class)
690     * @see RJInternal#JTAEX(JsonArray, int, Object, int, JsonValue.ValueType, JsonValue, Class)
691     */
692    protected static <T extends Number> T PARSE(
693            final JsonArray                 ja,
694            final int                       index,
695            final int                       FLAGS,
696            final T                         defaultValue,
697            final Class<T>                  returnClass,
698            final Function<String, T>       optionalParser,
699            final Function<BigDecimal, T>   defaultParser1,
700            final Function<BigDecimal, T>   defaultParser2
701        )
702    {
703        // When TRUE, the index provided turned out to be outside of the bounds of the array.  The
704        // IndexOutOfBounds "handler" (the method called here) will check the FLAGS, and:
705        //
706        //  1) return the defaultValue (if Requested by 'FLAGS' for IOOBEX)
707        //  2) return null (if Requested by 'FLAGS' for IOOBEX)
708        //  3) throw IndexOutOfBoundsException
709        //
710        // NOTE: It is probably a "little less efficient" to turn this into a method call,
711        //       since there are all these parameters that have to be passed, but this is
712        //       trading "readability" (less head-aches) in exchange for efficiency.
713        //
714        // This point applies to all of the "Exception Flag Handlers" used here
715
716        if (index >= ja.size()) return IOOBEX(ja, index, defaultValue, FLAGS);
717
718        final JsonValue jv = ja.get(index);
719
720        switch (jv.getValueType())
721        {
722            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullArrException 'handler'
723            // will do one of the following:
724            //
725            //  1) return the defaultValue (if Requested by 'FLAGS' for JNAEX)
726            //  2) return null (if Requested by 'FLAGS' for JNAEX)
727            //  3) throw JsonNullArrException
728
729            case NULL: return JNAEX(ja, index, defaultValue, FLAGS, STRING, returnClass);
730
731            case STRING:
732
733                final String s = ((JsonString) jv).getString();
734
735                // NOTE: This isn't actually an "Exception Case", and if the user hasn't made
736                //       a request, the empty-string is passed to whatever parser is configured
737
738                if (s.length() == 0)
739                {
740                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
741                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
742                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
743                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
744                }
745
746                // Temp Variable, used in order not to invoke the BigDecimal contructor twice
747                BigDecimal bd = null;
748
749                try
750                {
751                    // NOTE: 'bd' will not be null if "ArithmeticException" is thrown...
752                    // new BigDecimal throws "NumberFormatException" is thrown
753                    // optionalParser.apply can throw ArithmeticException
754
755                    return (optionalParser != null)
756                        ? optionalParser.apply(s)
757                        : defaultParser1.apply(bd = new BigDecimal(s.trim()));
758                }
759
760
761                // Because
762                //
763                // 1) A method for this code would only be invoked here, and...
764                // 2) And because there would be 9 parameters to pass, 
765                // 3) the 'inline' version of "Flag Handler" is left here!
766                //
767                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
768                //       are different for each of the 4 methods where they are used.
769
770                catch (ArithmeticException ae)
771                {
772                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
773                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
774                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)       return defaultParser2.apply(bd);
775                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
776                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
777
778                    throw new JsonArithmeticArrException(ae, ja, index, STRING, jv, returnClass);
779                }
780
781
782                // HANDLER STRIKES AGAIN! - but this time for "JsonStrParseArrException"
783                // RETURNS: null, or defaultValue, (otherwise throws JsonStrParseArrException)
784
785                catch (Exception e)
786                    { return JSPAEX(e, ja, index, defaultValue, FLAGS, jv, returnClass); }
787
788
789            // The JsonValue at the specified array-index does not contain an JsonString.
790            // The "JsonTypeArrException Handler" will do one of these:
791            //
792            //  1) return the defaultValue (if Requested by 'FLAGS' for JTAEX)
793            //  2) return null (if Requested by 'FLAGS' for JTAEX)
794            //  3) throw JsonTypeArrException
795
796            default: return JTAEX(ja, index, defaultValue, FLAGS, STRING, jv, returnClass);
797        }
798    }
799
800    /**
801     * Retrieve a {@link JsonObject} property containing a {@link JsonString}, and transform it to
802     * a <B STYLE='color: red'>Java Type</B>, with either a user-provided parser, or the standard
803     * java parser for that class (passed as a parameter).
804     * 
805     * @param <T> The type of the returned value.
806     * @param jo Any instance of {@link JsonObject}
807     * @param propertyName propertyName containing the {@link JsonString} to retrieve.
808     * @param FLAGS The return-value / exception-throw flag constants defined in {@link JFlag}
809     * @param defaultValue User-provided default-value, only returned if flags are set.
810     * @param optionalParser A valid {@code String -> 'T'} parser.  This parameter may be null.
811     * @param defaultParser1 Default {@code String -> 'T'} parser.
812     * @param defaultParser2 {@code String -> 'T'} parser, that will round on Arithmetic Exceptions
813     * 
814     * @return On success, this method returns the converted type instance.
815     * 
816     * @throws JsonPropMissingException {@code 'jo'} doesn't have {@code 'propertyName'}, unless
817     * flags are set.
818     * @throws JsonArithmeticObjException after parse, conversion fails, and flags aren't set
819     * @throws JsonStrParseObjException parser-failure unless flags are set
820     * @throws JsonNullObjException property contains null, unless flags are set
821     * @throws JsonTypeObjException property doesn't contain {@code JsonString}, unless flags are
822     * set.
823     * 
824     * @see #parseInteger(JsonObject, String, int, int, Function)
825     * @see #parseLong(JsonObject, String, int, long, Function)
826     * @see #parseShort(JsonObject, String, int, short, Function)
827     * @see #parseByte(JsonObject, String, int, byte, Function)
828     * @see #parseDouble(JsonObject, String, int, double, Function)
829     * @see #parseFloat(JsonObject, String, int, float, Function)
830     * 
831     * @see ReadNumberJSON#parse(JsonObject, String, int, Number, Function)
832     * 
833     * @see RJInternal#JPMEX(JsonObject, String, Object, int, JsonValue.ValueType, Class)
834     * @see RJInternal#JNOEX(JsonObject, String, Object, int, JsonValue.ValueType, Class)
835     * @see RJInternal#JSPOEX(Exception, JsonObject, String, Object, int, JsonValue, Class)
836     * @see RJInternal#JTOEX(JsonObject, String, Object, int, JsonValue.ValueType, JsonValue, Class)
837     */
838    protected static <T extends Number> T PARSE(
839            final JsonObject                jo,
840            final String                    propertyName,
841            final int                       FLAGS,
842            final T                         defaultValue,
843            final Class<T>                  returnClass,
844            final Function<String, T>       optionalParser,
845            final Function<BigDecimal, T>   defaultParser1,
846            final Function<BigDecimal, T>   defaultParser2
847        )
848    {
849        final JsonValue jv = jo.get(propertyName);
850
851
852        // When TRUE, the user-specified 'property' (named by 'propertyName') isn't actually one
853        // of the listed properties inside the JsonObject.  The JsonPropMissingException "handler"
854        // (the method called here) will check the FLAGS, and:
855        //
856        //  1) return the defaultValue (if Requested by 'FLAGS' for JPMEX)
857        //  2) return null (if Requested by 'FLAGS' for JPMEX)
858        //  3) throw JsonPropMissingException
859        //
860        // NOTE: It is probably a "little less efficient" to turn this into a method call,
861        //       since there are all these parameters that have to be passed, but this is
862        //       trading "readability" (less head-aches) in exchange for efficiency.
863        //
864        // This point applies to all of the "Exception Flag Handlers" used here
865
866        if (jv == null) return JPMEX(jo, propertyName, defaultValue, FLAGS, STRING, returnClass);
867
868        switch (jv.getValueType())
869        {
870            // When a 'NULL' (Json-Null) JsonValue is present, the JsonNullObjException 'handler'
871            // will do one of the following:
872            //
873            //  1) return the defaultValue (if Requested by 'FLAGS' for JNOEX)
874            //  2) return null (if Requested by 'FLAGS' for JNOEX)
875            //  3) throw JsonNullArrException
876
877            case NULL: return JNOEX(jo, propertyName, defaultValue, FLAGS, STRING, returnClass);
878
879            case STRING:
880
881                final String s = ((JsonString) jv).getString();
882
883
884                // NOTE: This isn't actually an "Exception Case", and if the user hasn't made
885                //       a request, the empty-string is passed to whatever parser is configured
886
887                if (s.length() == 0)
888                {
889                    if ((FLAGS & RETURN_NULL_ON_0LEN_STR) != 0)     return null;
890                    if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) != 0)   return defaultValue;
891                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
892                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
893                }
894
895                // Temp Variable, used in order not to invoke the BigDecimal contructor twice
896                BigDecimal bd = null;
897
898                try
899                {
900                    // NOTE: 'bd' will not be null if "ArithmeticException" is thrown...
901                    // new BigDecimal throws "NumberFormatException" is thrown
902                    // parsoptionalParserer.apply can throw ArithmeticException
903
904                    return (optionalParser != null)
905                        ? optionalParser.apply(s)
906                        : defaultParser1.apply(bd = new BigDecimal(s.trim()));
907                }
908
909
910                // Because
911                //
912                // 1) A method for this code would only be invoked here, and...
913                // 2) And because there would be 9 parameters to pass, 
914                // 3) the 'inline' version of "Flag Handler" is left here!
915                //
916                // NOTE: All four "JsonArithmetic Arr/Obj Exception" exception throws
917                //       are different for each of the 4 methods where they are used.
918
919                catch (ArithmeticException ae)
920                {
921                    if ((FLAGS & RETURN_NULL_ON_AEX) != 0)          return null;
922                    if ((FLAGS & RETURN_DEFVAL_ON_AEX) != 0)        return defaultValue;
923                    if ((FLAGS & RETURN_JAPPROX_ON_AEX) != 0)       return defaultParser2.apply(bd);
924                    if ((FLAGS & RETURN_NULL_ON_ANY_ALL) != 0)      return null;
925                    if ((FLAGS & RETURN_DEFVAL_ON_ANY_ALL) != 0)    return defaultValue;
926
927                    throw new JsonArithmeticObjException
928                        (ae, jo, propertyName, STRING, jv, returnClass);
929                }
930
931
932                // HANDLER STRIKES AGAIN! - but this time for "JsonStrParseObjException"
933                // RETURNS: null, or defaultValue, (otherwise throws JsonStrParseObjException)
934
935                catch (Exception e)
936                    { return JSPOEX(e, jo, propertyName, defaultValue, FLAGS, jv, returnClass); }
937
938
939            // The JsonValue of 'propertyName' does not contain an JsonString.
940            // The "JsonTypeObjException Handler" will do one of these:
941            //
942            //  1) return the defaultValue (if Requested by 'FLAGS' for JTOEX)
943            //  2) return null (if Requested by 'FLAGS' for JTOEX)
944            //  3) throw JsonTypeObjException
945
946            default: return JTOEX(jo, propertyName, defaultValue, FLAGS, STRING, jv, returnClass);
947        }
948    }
949
950
951    // ********************************************************************************************
952    // ********************************************************************************************
953    // HELPER PARSE #2 - JsonString Inputs (WITHOUT FLAGS)
954    // ********************************************************************************************
955    // ********************************************************************************************
956
957
958    /**
959     * This is an internal helper method for retrieving an element from a {@link JsonArray},
960     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
961     *  
962     * @param <T>           Numeric Boxed-Type, as an instance of {@code java.lang.Class}
963     * @param ja            Any instance of {@link JsonArray}
964     * @param index         A valid index into {@code 'ja'}
965     * @param returnClass   Internally specified Numeric Boxed-Type, used for Type Inference
966     * @param parser        <EMBED CLASS='external-html' DATA-FILE-ID=COMMON_PARSER>
967     * 
968     * @return The converted number, as an instance of Generic-Parameter {@code 'T'}
969     * 
970     * @see #parseInteger(JsonArray, int)
971     * @see #parseLong(JsonArray, int)
972     * @see #parseShort(JsonArray, int)
973     * @see #parseByte(JsonArray, int)
974     * @see #parseDouble(JsonArray, int)
975     * @see #parseFloat(JsonArray, int)
976     */
977    protected static <T extends Number> T PARSE_NO_FLAGS(
978            final JsonArray             ja,
979            final int                   index,
980            final Class<T>              returnClass,
981            final Function<String, T>   parser
982        )
983    {
984        // Throws an IndexOutOfBoundsException
985        final JsonValue jv = ja.get(index);
986
987        switch (jv.getValueType())
988        {
989            case NULL: return null;
990
991            case STRING:
992
993                try
994                    { return parser.apply(((JsonString) jv).getString()); }
995
996                catch (ArithmeticException ae)
997                    { throw new JsonArithmeticArrException(ae, ja, index, STRING, jv, returnClass);}
998
999                catch (Exception e)
1000                    { throw new JsonStrParseArrException (e, ja, index, jv, returnClass); }
1001
1002            default: throw new JsonTypeArrException(ja, index, STRING, jv, returnClass);
1003        }
1004    }
1005
1006
1007    /**
1008     * This is an internal helper method for retrieving a property from a {@link JsonObject},
1009     * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>.
1010     * 
1011     * @param <T>           Numeric Boxed-Type, as an instance of {@code java.lang.Class}
1012     * @param jo            Any instance of {@link JsonObject}
1013     * @param propertyName  Any property name contained by {@code 'jo'}
1014     * @param isOptional    <EMBED CLASS='external-html' DATA-FILE-ID=COMMON_IS_OPTIONAL>
1015     * @param parser        <EMBED CLASS='external-html' DATA-FILE-ID=COMMON_PARSER>
1016     * 
1017     * @return The converted number, as an instance of Generic-Parameter {@code 'T'}
1018     * 
1019     * @see #parseInteger(JsonObject, String, boolean)
1020     * @see #parseLong(JsonObject, String, boolean)
1021     * @see #parseShort(JsonObject, String, boolean)
1022     * @see #parseByte(JsonObject, String, boolean)
1023     * @see #parseDouble(JsonObject, String, boolean)
1024     * @see #parseFloat(JsonObject, String, boolean)
1025     */
1026    protected static <T extends Number> T PARSE_NO_FLAGS(
1027            final JsonObject            jo,
1028            final String                propertyName,
1029            final boolean               isOptional,
1030            final Class<T>              returnClass,
1031            final Function<String, T>   parser
1032        )
1033    {
1034        final JsonValue jv = jo.get(propertyName);
1035
1036        if (jv == null)
1037        {
1038            if (isOptional)
1039                return null;
1040            else
1041                throw new JsonPropMissingException(jo, propertyName, STRING, returnClass);
1042        }
1043
1044        switch (jv.getValueType())
1045        {
1046            case NULL: return null;
1047
1048            case STRING:
1049
1050                try
1051                    { return parser.apply(((JsonString) jv).getString()); }
1052
1053                catch (ArithmeticException ae)
1054                {
1055                    throw new JsonArithmeticObjException
1056                        (ae, jo, propertyName, STRING, jv, returnClass);
1057                }
1058
1059                catch (Exception e)
1060                    { throw new JsonStrParseObjException(e, jo, propertyName, jv, returnClass); }
1061
1062            default: throw new JsonTypeObjException(jo, propertyName, STRING, jv, returnClass);
1063        }
1064    }
1065
1066}