001package Torello.Java.JSON;
002
003import Torello.Java.StringParse;
004import Torello.Java.UnreachableError;
005
006import Torello.Java.Additional.Ret3;
007import Torello.Java.Additional.EffectivelyFinal;
008import Torello.Java.Additional.Counter;
009
010import Torello.Java.Function.ToByteFunction;
011import Torello.Java.Function.ToFloatFunction;
012import Torello.Java.Function.ToShortFunction;
013
014import java.util.*;
015import java.util.stream.*;
016import java.util.function.*;
017import java.math.*;
018import javax.json.*;
019
020import java.lang.reflect.Array;
021
022// This is "The Great Sillyness" - it is only used because of the Java-Quirk about constructor's
023// not referencing "this" before a call to "super(...)" or "this(...)".  The only way around it I
024// have ever found is to use a static-temporary variable, and set its value inside of a static
025// helper-method.
026//
027// This is, essentially, just fine.  However, if the user ever ran this in a multi-threaded program
028// it might "get messed up".  TO PREVENT THAT: You have to have a few lines that are synchronized.
029// Using the "ReentrantLock" is easier for me to think about than using "synchronized"
030//
031// NOTE: There is NO MULTI-THREADED CALLS IN THIS CLASS WHATSOEVER.  This is only used as a 
032//       "Constructor-Helper"
033//
034// THIS CLASS IS **VERY** THREAD-SAFE
035
036import java.util.concurrent.locks.ReentrantLock;
037
038import static javax.json.JsonValue.ValueType.*;
039import static Torello.Java.JSON.JFlag.*;
040
041/**
042 * Utilities for parsing Json Array's into Java Array's.
043 * 
044 * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE>
045 * <EMBED CLASS='external-html' DATA-FILE-ID=READ_ARR_JSON>
046 *
047 * @see Json
048 * @see Json
049 * @see JsonArray
050 */
051@Torello.JavaDoc.StaticFunctional
052@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI")
053public class ReadArrJSON
054{
055    private ReadArrJSON() { }
056
057    // ********************************************************************************************
058    // ********************************************************************************************
059    // TEST-PREDICATE'S
060    // ********************************************************************************************
061    // ********************************************************************************************
062
063
064    private static final BigInteger LONG_MAX    = BigInteger.valueOf(Long.MAX_VALUE);
065    private static final BigInteger LONG_MIN    = BigInteger.valueOf(Long.MIN_VALUE);
066    private static final BigInteger SHORT_MAX   = BigInteger.valueOf(Short.MAX_VALUE);
067    private static final BigInteger SHORT_MIN   = BigInteger.valueOf(Short.MIN_VALUE);
068    private static final BigInteger BYTE_MAX    = BigInteger.valueOf(Byte.MAX_VALUE);
069    private static final BigInteger BYTE_MIN    = BigInteger.valueOf(Byte.MIN_VALUE);
070
071    /** 
072     * These are eliminated / removed from any call to a method which returns either an array
073     * of Java Primitives or a Java Primitive Stream
074     * 
075     * @see #intArrayToStream(JsonArray, int, int, ToIntFunction)
076     * @see #longArrayToStream(JsonArray, long, int, ToLongFunction)
077     * @see #doubleArrayToStream(JsonArray, double, int, ToDoubleFunction)
078     * @see #byteArray(JsonArray, byte, int, ToByteFunction)
079     * @see #floatArray(JsonArray, float, int, ToFloatFunction)
080     * @see #shortArray(JsonArray, short, int, ToShortFunction)
081     * @see #booleanArray(JsonArray, boolean, int, Predicate)
082     */
083    public static final int NOT_ALLOWED_RET_NULL_MASKS = ~(RETURN_NULL_ON_ANY_ALL |
084        RETURN_NULL_ON_AEX | RETURN_NULL_ON_NULL | RETURN_NULL_ON_SPEX | RETURN_NULL_ON_STR |
085        RETURN_NULL_ON_0LEN_STR | RETURN_NULL_ON_WRONG_JSONTYPE | INSERT_NULL_ON_NON_SUBARRAY_TYPE);
086
087
088    // For "Integer", the javax.json will always return an instance of "Integer" if the JsonNumber
089    // is, indeed, a valid Integer.  This doesn't work for Long - even though java.json will return
090    // an instance of boxed-type "Long" when the number is a Long because if the user has requested
091    // a LongStream, and an Integer was parsed (because the number was between 0 and MAX_INT), then
092    // just checking the Class of the returned value will fail.
093    //
094    // Converting to a returned "Integer" or "Long" to a "BigInteger" is extremely cheap, and fast,
095    // since the class BigInteger will just save the "Integer" internally.
096
097
098    private static boolean shortTypePred(JsonNumber jn)
099    {
100        if (! jn.isIntegral()) return false;
101
102        BigInteger bi = jn.bigIntegerValue();
103        int signum = bi.signum();
104
105        return  ((signum > 0) && (bi.compareTo(SHORT_MAX) <= 0))
106            ||  ((signum < 0) && (bi.compareTo(SHORT_MIN) >= 0))
107            ||  (signum == 0);
108    }
109
110    private static boolean byteTypePred(JsonNumber jn)
111    {
112        if (! jn.isIntegral()) return false;
113
114        BigInteger bi = jn.bigIntegerValue();
115        int signum = bi.signum();
116
117        return  ((signum > 0) && (bi.compareTo(BYTE_MAX) <= 0))
118            ||  ((signum < 0) && (bi.compareTo(BYTE_MIN) >= 0))
119            ||  (signum == 0);
120    }
121
122    private static boolean doubleTypePred(JsonNumber jn)
123    { return true; /* for now!  Only bizzare & egregious cases won't fit into a double... */ }
124
125    private static boolean floatTypePred(JsonNumber jn)
126    { return true; }
127
128    private static boolean longTypePred(JsonNumber jn)
129    {
130        if (! jn.isIntegral()) return false;
131
132        BigInteger bi = jn.bigIntegerValue();
133        int signum = bi.signum();
134
135        return  ((signum > 0) && (bi.compareTo(LONG_MAX) <= 0))
136            ||  ((signum < 0) && (bi.compareTo(LONG_MIN) >= 0))
137            ||  (signum == 0);
138    }
139
140
141    // ********************************************************************************************
142    // ********************************************************************************************
143    // HELPER-RECORD
144    // ********************************************************************************************
145    // ********************************************************************************************
146
147
148    // NOTE: It is **A LOT** Smarter to check for the exception instead of using the try-catch
149    //       since I have read that generating an exception is one of the most costly-expensive
150    //       things the JRE does.  It isn't the Exception-Constructor that costs a lot - it is the
151    //       creating of the **STACK-TRACE** that costs well over 100 to 1,000 times the number of
152    //       of CPU-Cycles that the cost of a simple constructor.  This is an "Only if abolutely"
153    //       necessary things.
154
155    private static <T extends Number> ArithmeticException getAEX
156        (JsonNumber jn, Function<BigDecimal, ?> converter)
157    {
158        try
159            { converter.apply(jn.bigDecimalValue()); }
160        catch (ArithmeticException aex)
161            { return aex; }
162
163        throw new UnreachableError();
164    }
165
166    private static Exception getSPEX(String s, Function<String, ?> converter)
167    {
168        try
169            { converter.apply(s); }
170        catch (Exception e)
171            { return e; }
172
173        throw new UnreachableError();
174    }
175
176
177    // ********************************************************************************************
178    // ********************************************************************************************
179    // RECORD Configuration-Class
180    // ********************************************************************************************
181    // ********************************************************************************************
182
183
184    private static class RECORD<T, U>
185    {
186        // Assigned after construction, cannot be final
187        private JsonArray ja;
188
189        private final T defaultValue;
190
191        private final boolean RJA_AEX, RTS_WT, IN_NSAT, S_NSAT;
192
193        private final Runnable handlerNull, handlerAEX, handlerSPEX, handlerZLS, handlerWrongType;
194        private final ObjIntConsumer<JsonValue> handlerJsonString;
195
196        private final Class<T>                  CLASS;
197        private final Predicate<JsonNumber>     jsonNumWillFit;
198        private final Predicate<String>         validStrTester;
199        private final Function<String, T>       defaultParser;
200        private final Function<Number, T>       numberConverter;
201        private final Function<BigDecimal, T>   numberConverterExThrow;
202        private final Function<String, T>       userParser;
203
204        // NOTE: This class "RECORD" can handle the standard "Stream<T>", but it can also handle
205        //       the three primitive-Stream's: IntStream, LongStream and DoubleStream.
206        //
207        // Therefore these are kept as separate function-pointers.  If it weren't for those three
208        // primitive-streams, this would be completely unnecessary.   YES, this class is a little
209        // hard to read.
210
211        private final Runnable      c;  // Stream.builder()
212        private final Consumer<T>   a;  // Stream.Builder.accept(T)
213        private final Supplier<U>   b;  // Stream.Builder.build()
214
215
216        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
217        // This is only used by the methods in the nested-class "DimN"
218        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
219        //
220        // This is not final, because it is set after the constructor. 
221        //
222        // Since the user is incapable of accessing any of this, and since great care has been 
223        // taken to rigorously test all of this stuff, it is basically unimportant.
224
225        private Function<JsonArray, Object> array1DGenerator = null;
226
227
228        // ****************************************************************************************
229        // ****************************************************************************************
230        // PRIMARY RECORD Constructor
231        // ****************************************************************************************
232        // ****************************************************************************************
233
234
235        private RECORD(
236                T                       defaultValue,
237                int                     FLAGS,
238
239                Class<T>                CLASS,
240                Predicate<JsonNumber>   jsonNumWillFit,
241                Predicate<String>       validStrTester,
242                Function<String, T>     defaultParser,
243                Function<Number, T>     numberConverter,
244                Function<BigDecimal, T> numberConverterExThrow,
245                Function<String, T>     userParser,
246                boolean                 NULLS,
247
248                Runnable                streamConstructor,
249                Consumer<T>             streamAcceptor,
250                Supplier<U>             streamBuilder
251            )
252        {
253            this.defaultValue           = defaultValue;     // User-Provided Default-Value
254            this.CLASS                  = CLASS;            // Class of the Stream.Builder "accept" Parameter
255            this.jsonNumWillFit         = jsonNumWillFit;   // Checks if JsonNumber will fit properly
256            this.validStrTester         = validStrTester;   // Used for Verifying a JsonString
257            this.defaultParser          = defaultParser;    // Default JsonString Parser to Number
258            this.numberConverter        = numberConverter;  // interface java.lang.Number method
259            this.numberConverterExThrow = numberConverterExThrow;
260            this.userParser             = userParser;       // Optional User Parser
261
262            this.c = streamConstructor;    // Stream.builder()
263            this.a = streamAcceptor;       // Stream.Builder.accept()
264            this.b = streamBuilder;        // Stream.Builder.build()
265
266            this.RJA_AEX    = (FLAGS & RETURN_JAPPROX_ON_AEX) > 0;
267            this.RTS_WT     = (FLAGS & RETURN_TOSTRING_ON_WRONGTYPE) > 0;
268            this.IN_NSAT    = (FLAGS & INSERT_NULL_ON_NON_SUBARRAY_TYPE) > 0;
269            this.S_NSAT     = (FLAGS & SKIP_ON_NON_SUBARRAY_TYPE) > 0;
270
271            boolean RN_AA   = NULLS && ((FLAGS & RETURN_NULL_ON_ANY_ALL) > 0);
272            boolean RD_AA   = (FLAGS & RETURN_DEFVAL_ON_ANY_ALL) > 0;
273            boolean S_AA    = (FLAGS & SKIP_ON_ANY_ALL) > 0;
274
275            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
276            // Null Handler (JsonNull was in the JsonArray)
277            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
278            //
279            // NOTE: AN(), AD() and NOOP() are just one-line private methods that:
280            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
281
282            if (NULLS && ((FLAGS & RETURN_NULL_ON_NULL) > 0))   handlerNull = this::AN;
283            else if ((FLAGS & RETURN_DEFVAL_ON_NULL) > 0)       handlerNull = this::AD;
284            else if ((FLAGS & SKIP_ON_NULL) > 0)                handlerNull = this::NOOP;
285            else if (NULLS && RN_AA)                            handlerNull = this::AN;
286            else if (RD_AA)                                     handlerNull = this::AD;
287            else if (S_AA)                                      handlerNull = this::NOOP;
288            else if (NULLS)                                     handlerNull = this::AN;
289            else                                                handlerNull = null;
290
291
292            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
293            // AEX Handler (ArithmeticException)
294            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
295            //
296            // NOTE: AN(), AD() and NOOP() are just one-line private methods that:
297            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
298
299            if (NULLS && ((FLAGS & RETURN_NULL_ON_AEX) > 0))    handlerAEX = this::AN;
300            else if ((FLAGS & RETURN_DEFVAL_ON_AEX) > 0)        handlerAEX = this::AD;
301            else if ((FLAGS & SKIP_ON_AEX) > 0)                 handlerAEX = this::NOOP;
302            else if (NULLS && RN_AA)                            handlerAEX = this::AN;
303            else if (RD_AA)                                     handlerAEX = this::AD;
304            else if (S_AA)                                      handlerAEX = this::NOOP;
305            else                                                handlerAEX = null;
306
307
308            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
309            // SPEX Handler (Exception while parsing a String into the Java-Type)
310            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
311            //
312            // NOTE: AN(), AD() and NOOP() are just one-line private methods that:
313            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
314
315            if (NULLS && ((FLAGS & RETURN_NULL_ON_SPEX) > 0))   handlerSPEX = this::AN;
316            else if ((FLAGS & RETURN_DEFVAL_ON_SPEX) > 0)       handlerSPEX = this::AD;
317            else if ((FLAGS & SKIP_ON_SPEX) > 0)                handlerSPEX = this::NOOP;
318            else if (NULLS && RN_AA)                            handlerSPEX = this::AN;
319            else if (RD_AA)                                     handlerSPEX = this::AD;
320            else if (S_AA)                                      handlerSPEX = this::NOOP;
321            else                                                handlerSPEX = null;
322
323
324            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
325            // ZLS Handler (A Zero-Length String was in the JsonArray)
326            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
327            //
328            // NOTE: AN(), AD() and NOOP() are just one-line private methods that:
329            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
330
331            if (NULLS && ((FLAGS & RETURN_NULL_ON_0LEN_STR) > 0))   handlerZLS = this::AN;
332            else if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) > 0)       handlerZLS = this::AD;
333            else if ((FLAGS & SKIP_ON_0LEN_STR) > 0)                handlerZLS = this::NOOP;
334            else if (NULLS && RN_AA)                                handlerZLS = this::AN;
335            else if (RD_AA)                                         handlerZLS = this::AD;
336            else if (S_AA)                                          handlerZLS = this::NOOP;
337            else                                                    handlerZLS = null;
338
339
340            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
341            // Wrong-Type Handler (A JsonObject or a nested-JsonArray was in an array position)
342            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
343            //
344            // NOTE: AN(), AD() and NOOP() are just one-line private methods that:
345            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
346            //
347            // ALSO: RN_WT & RD_WT are the abbreviated-flags for "ON_WRONG_JSONTYPE"
348
349            if (NULLS && ((FLAGS & RN_WT) > 0))             handlerWrongType = this::AN;
350            else if ((FLAGS & RD_WT) > 0)                   handlerWrongType = this::AD;
351            else if ((FLAGS & SKIP_ON_WRONG_JSONTYPE) > 0)  handlerWrongType = this::NOOP;
352            else if (NULLS && RN_AA)                        handlerWrongType = this::AN;
353            else if (RD_AA)                                 handlerWrongType = this::AD;
354            else if (S_AA)                                  handlerWrongType = this::NOOP;
355            else                                            handlerWrongType = null;
356
357
358            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
359            // JsonString Handler (This was *ALSO* moved here to get rid of more of the if's)
360            // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
361            //
362            // NOTE: AN(JsonValue, int), AD(JsonValue, int) and NOOP(JsonValue, int) are just
363            //       one-line private methods that:
364            //       a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP)
365
366            if (userParser != null)         handlerJsonString = this::useUserParser;
367            else if ((FLAGS & RP_S) > 0)    handlerJsonString = this::parseString;
368            else if (NULLS && ((FLAGS & RETURN_NULL_ON_STR) > 0))   handlerJsonString = this::AN;
369            else if ((FLAGS & RETURN_DEFVAL_ON_STR) > 0)            handlerJsonString = this::AD;
370            else if ((FLAGS & SKIP_ON_STR) > 0)                     handlerJsonString = this::NOOP;
371            else if (NULLS && RN_AA)                                handlerJsonString = this::AN;
372            else if (RD_AA)                                         handlerJsonString = this::AD;
373            else if (S_AA)                                          handlerJsonString = this::NOOP;
374            else handlerJsonString = (JsonValue jv, int i) ->
375                { throw new JsonTypeArrException (this.ja, i, NUMBER, jv, this.CLASS); };
376        }
377
378
379        // ****************************************************************************************
380        // ****************************************************************************************
381        // Boxed-Primitive Stream RECORD Contructor
382        // ****************************************************************************************
383        // ****************************************************************************************
384
385
386        @SuppressWarnings({"unchecked"})
387        private RECORD(
388                T                       defaultValue,
389                int                     FLAGS,
390
391                Class<T>                CLASS,
392                Predicate<JsonNumber>   jsonNumWillFit,
393                Predicate<String>       validStrTester,
394                Function<String, T>     defaultParser,
395                Function<Number, T>     numberConverter,
396                Function<BigDecimal, T> numberConverterExThrow,
397                Function<String, T>     userParser
398            )
399        {
400            this(
401                defaultValue, FLAGS,
402
403                CLASS, jsonNumWillFit, validStrTester, defaultParser, numberConverter,
404                numberConverterExThrow, userParser, true,
405
406                constructorHelper(new EffectivelyFinal<>(null)),//, CLASS, Stream.class),
407                (Consumer<T>)   constructorHelper.b,    // Un-Checked Cast
408                (Supplier<U>)   constructorHelper.c     // Un-Checked Cast
409            );
410
411            // Essentially, the lock is only used for about three instructions that are inside the
412            // method "constructorHelper".  It, sort-of, "borrows" a private static-field for just
413            // a moment, so that the values can be passed to the call to "this(...)", which is
414            // just  "kind-of" faking out the compiler so I can do some processing before calling
415            // "this(...)" as above
416            //
417            // Now that the loan-out is over, unlock the lock, and it can be used in another call
418
419            lock.unlock();
420
421            // THIS CLASS *IS* THREAD SAFE, 
422            // THIS Nested-Class "RECORD" IS NOT THREAD-SAFE - EXCEPT THE USER IS NOT ALLOWED ACCESS,
423            // AND MAY NOT OBTAIN AN INSTNANCE OF "RECORD", so it all works just fine, even in a
424            // multi-threaded program!
425
426            /*
427            // OLD CODE - DON'T ERASE THIS, EVEN BEFORE THE LOCK, THIS WAS KIND OF UGLY
428
429            final EffectivelyFinal<Stream.Builder<T>> EFSB = new EffectivelyFinal<>(null);
430
431            this.c = ()     -> EFSB.f = Stream.builder();
432            this.a = (T t)  -> EFSB.f.accept(t);
433            this.b = ()     -> (U) EFSB.f.build();
434            */
435        }
436
437        // These are the "Contructor Helpers" that are mentioned at the top of this class (in the
438        // "import-statement" section).  These are just here to help by-pass the Java Requirement
439        // that calls to "this(...)" and "super(...)" occur on the first line.
440
441        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
442        // This is NOT TO BE UNDERSTOOD BY MORTAL-MEN, SO DON'T ASK
443        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
444        //
445        // The **MAIN-POINT** of all this non-sense is that at **RUNTIME** (as you should know by
446        // by now) all Generic-Type Information has been erased.  An instance of class Object is
447        // no different than an instance of class String, Integer or anything else.  It is just a
448        // pointer to a class.
449        //
450        // This whole thing is just "Faking Out The Compiler"
451        //
452        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
453        // Mostly, I am very used to having all the fields in Class "RECORD" being declared FINAL
454        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
455        //
456        // It is very soothing to know that the constructor is "setting everything up", and the
457        // Json-Processor stuff isn't going to do anything with the configurations (because they
458        // are all declared FINAL).
459
460        private static final ReentrantLock lock = new ReentrantLock();
461
462        @SuppressWarnings("rawtypes")
463        private static Ret3 constructorHelper;
464
465        @SuppressWarnings({"rawtypes", "unchecked"})
466        private static Runnable constructorHelper(final EffectivelyFinal<Stream.Builder> EFSB)
467        {
468            lock.lock();
469
470            // If you don't understand this line, oh well...
471            //
472            // This was "built" or "developed" in a step-wise fasion.
473            // There is a WHOLE-BUNCH of testing code, and it all worked.  All this 'type-magic' is
474            // doing is tricking the java compiler, so I can have my way.
475            //
476            // Every time I play with the types, I go back and run a GIANT-STACK of TEST
477            // PROCEDURES.  If they all work, I know this works.  This is **NOT REALLY** a good
478            // software-writing  practice, **HOWEVER** Java-Generics are sometimes a real problem.
479            //
480            // The purpose of having TYPES in a programming language is to help catch programming
481            // errors early-on at compile-time.  Java does this pretty well, but when things get
482            // advanced (it is always with Function-Pointers - a.k.a. "Functional-Interfaces" and
483            // Lambda-Expressions)... when things get "ADVANCED" it is sometimes a little
484            // ridiculours.
485            //
486            // When they say that Java-Script is a "TYPE-LESS" language at that it is easier, well,
487            // Java-Script has tons of Run-Time errors that can be impossible to debug/find!
488            //
489            // There is no real-way that I can think of to "improve" generics, because all the are
490            // in the first-place is a little "Help Finding the Errors" at Compile-Time thing...
491
492            constructorHelper = new Ret3<Runnable, Consumer, Supplier>(
493                (Runnable)  (()         -> EFSB.f = Stream.builder()),
494                (Consumer)  ((Object o) -> EFSB.f.accept(o)),
495                (Supplier)  (()         -> /*(B)*/ EFSB.f.build())
496            );
497
498            return (Runnable) constructorHelper.a;
499        }
500
501
502        // ****************************************************************************************
503        // ****************************************************************************************
504        // HELPER'S FOR THE HANDLERS
505        // ****************************************************************************************
506        // ****************************************************************************************
507
508        private void AN()   { a.accept(null); }
509        private void AD()   { a.accept(defaultValue); }
510        private void NOOP() { }
511
512        private void AN(JsonValue jv, int i)    { a.accept(null); }
513        private void AD(JsonValue jv, int i)    { a.accept(defaultValue); }
514        private void NOOP(JsonValue jv, int i)  { }
515
516        private void useUserParser(JsonValue jv, int i)
517        {
518            try
519            {
520                this.a.accept
521                    (this.userParser.apply(((JsonString) jv).getString()));
522            }
523
524            catch (Exception e)
525            {
526                if (this.handlerSPEX != null) this.handlerSPEX.run();
527                else throw new JsonStrParseArrException(e, this.ja, i, jv, this.CLASS);
528            }
529        };
530
531        private void parseString(JsonValue jv, int i)
532        {
533            String s = ((JsonString) jv).getString();
534
535            if (s.length() == 0)
536            {
537                if (this.handlerZLS != null) this.handlerZLS.run();
538
539                else throw new JsonStrParseArrException(
540                    new IllegalArgumentException("Zero Length String"),
541                    this.ja, i, jv, this.CLASS
542                );
543            }
544
545            // StringParse.isInteger(s), isLong(String) **AND** s -> true (Double)
546            else if (this.validStrTester.test(s))
547
548                // Integer.parseInt(String), Long.parseLong, Double.parseDouble
549                this.a.accept(this.defaultParser.apply(s));
550
551            else if (this.handlerSPEX != null) this.handlerSPEX.run();
552
553            else throw new JsonStrParseArrException
554                (getSPEX(s, this.defaultParser), this.ja, i, jv, this.CLASS);
555        }
556
557
558        // ****************************************************************************************
559        // ****************************************************************************************
560        // Static RECORD Factory/Builder Methods  --  Primitive-Streams
561        // ****************************************************************************************
562        // ****************************************************************************************
563
564
565        private static RECORD<Integer, IntStream> getIntStreamRec
566            (int defaultValue, int FLAGS, ToIntFunction<String> optionalUserParser)
567        {
568            EffectivelyFinal<IntStream.Builder> EFISB = new EffectivelyFinal<>(null);
569
570            RECORD<Integer, IntStream> rec = new RECORD<>(
571                defaultValue, 
572                FLAGS,
573
574                // The class of the (only) parameter to the Stream.Builder "accept" method
575                int.class,
576
577                // A simple way to test if there will be an "ArithmeticException"
578                // Somewhat "counter-intuitive", but it works great...
579
580                (JsonNumber jn) -> Integer.class == jn.numberValue().getClass(),
581
582                StringParse::isInteger,     // number-string-tester
583                Integer::parseInt,          // default-parser (string to int)
584                Number::intValue,           // numberConverter
585                BigDecimal::intValueExact,  // cause AEX (ArithmeticException)
586
587                // Parse Number-Strings (this may be null)
588                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
589
590                (optionalUserParser != null)
591                    ? (String s) -> optionalUserParser.applyAsInt(s)
592                    : null, 
593
594                // Primitive (nulls not allowed)
595                false,
596
597                ()          -> EFISB.f = IntStream.builder(),   // Stream.Builder constructor
598                (Integer x) -> EFISB.f.accept(x),               // Builder "accept" Function-Ptr
599                ()          -> EFISB.f.build()                  // Builder "build" Function-Ptr
600            );
601
602            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
603            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON
604
605            rec.array1DGenerator =
606                (JsonArray ja) -> jsonArrToStream(ja, rec).toArray();
607
608            return rec;
609        }
610
611        private static RECORD<Long, LongStream> getLongStreamRec
612            (long defaultValue, int FLAGS, ToLongFunction<String> optionalUserParser)
613        {
614            EffectivelyFinal<LongStream.Builder> EFLSB = new EffectivelyFinal<>(null);
615    
616            RECORD<Long, LongStream> rec = new RECORD<>(
617                defaultValue,
618                FLAGS,
619
620                long.class,                 // Class of the Stream.Builder "accept" Parameter
621                ReadArrJSON::longTypePred,  // Checks the JsonNumber retrieved
622                StringParse::isLong,        // String-tester (for parsing number-strings)
623                Long::parseLong,            // default-parser (number-string to long)
624                Number::longValue,          // numberConverter
625                BigDecimal::longValueExact, // Generates AEX (ArithmeticException)
626
627                // Parse Number-Strings (this may be null)
628                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
629
630                (optionalUserParser != null)
631                    ? (String s) -> optionalUserParser.applyAsLong(s)
632                    : null,
633
634                // Primitive (nulls not allowed)
635                false,
636
637                () ->       EFLSB.f = LongStream.builder(), // Stream.Builder constructor
638                (Long x) -> EFLSB.f.accept(x),              // Builder "accept" Function-Pointer
639                () ->       EFLSB.f.build()                 // Builder "build" Function-Pointer
640            );
641
642            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
643            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON
644
645            rec.array1DGenerator =
646                (JsonArray ja) -> jsonArrToStream(ja, rec).toArray();
647
648            return rec;
649        }
650
651        private static RECORD<Double, DoubleStream> getDoubleStreamRec
652            (double defaultValue, int FLAGS, ToDoubleFunction<String> optionalUserParser)
653        {
654            EffectivelyFinal<DoubleStream.Builder> EFDSB = new EffectivelyFinal<>(null);
655
656            RECORD<Double, DoubleStream> rec = new RECORD<>(
657                defaultValue,
658                FLAGS,
659
660                double.class,                   // Stream.Builder "accept" Parameter-Class
661                ReadArrJSON::doubleTypePred,    // Checks the JsonNumber retrieved
662                StringParse::isDouble,          // String-tester (for parsing number-strings)
663                Double::parseDouble,            // default-parser (number-string to double)
664                (Number n) -> n.doubleValue(),  // numberConverter
665
666                // Generate an AEX if the "StringParse.isDouble" failed
667                (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); },
668
669                // Parse Number-Strings (this may be null)
670                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
671
672                (optionalUserParser != null)
673                    ? (String s) -> optionalUserParser.applyAsDouble(s)
674                    : null,
675
676                // Primitive (nulls not allowed)
677                false,
678
679                ()          -> EFDSB.f = DoubleStream.builder(),    // Stream.Builder constructor
680                (Double x)  -> EFDSB.f.accept(x),                   // Builder "accept" FunctionPtr
681                ()          -> EFDSB.f.build()                      // Builder "build" FunctionPtr
682            );
683
684            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
685            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON
686
687            rec.array1DGenerator =
688                (JsonArray ja) -> jsonArrToStream(ja, rec).toArray();
689
690            return rec;
691        }
692
693
694        // ****************************************************************************************
695        // ****************************************************************************************
696        // Static RECORD Factory/Builder Methods  --  Boxed-Primitive-Streams
697        // ****************************************************************************************
698        // ****************************************************************************************
699
700
701        private static RECORD<Integer, Stream<Integer>> getINTEGERStreamRec
702            (int defaultValue, int FLAGS, Function<String, Integer> optionalUserParser)
703        {
704            RECORD<Integer, Stream<Integer>> rec = new RECORD<>(
705                defaultValue,
706                FLAGS,
707                Integer.class,              // Class of the Stream.Builder "accept" Parameter
708                (JsonNumber jn) -> jn.numberValue().getClass() == Integer.class,
709                StringParse::isInteger,     // String-tester (for parsing number-strings)
710                Integer::parseInt,          // default-parser (number-string to Integer)
711                Number::intValue,           // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
712                BigDecimal::intValueExact,  // Generates AEX on fail
713                optionalUserParser
714            );
715
716            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
717            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON.
718            // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 
719            // primitive "int[]" array (rather than an "Integer[]"), "IntStream.toArray" is used
720
721            rec.array1DGenerator = (JsonArray ja) ->
722                jsonArrToBoxedStream(ja, rec).toArray(Integer[]::new);
723
724            return rec;
725        }
726
727        private static RECORD<Short, Stream<Short>> getSHORTStreamRec(
728                short defaultValue, int FLAGS, Function<String, Short> optionalUserParser,
729                boolean primitiveOrBoxedOutput1DArray
730            )
731        {
732            RECORD<Short, Stream<Short>> rec = new RECORD<>(
733                defaultValue,
734                FLAGS,
735                Short.class,                    // Class of the Stream.Builder "accept" Parameter
736                ReadArrJSON::shortTypePred,     // Checks the JsonNumber retrieved
737                StringParse::isShort,           // String-tester (for parsing number-strings)
738                Short::parseShort,              // default-parser (number-string to short)
739                Number::shortValue,             // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
740                BigDecimal::shortValueExact,    // Generates AEX on fail
741                optionalUserParser
742            );
743
744            // Only used by "DimN" Sub-Class.  It builds the 1D arrays.  Since short's do not have
745            // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be
746            // used to dispatch-build *BOTH* a short[] and a Short[]
747
748            rec.array1DGenerator = primitiveOrBoxedOutput1DArray
749                ? rec::array1DGeneratorShort
750                : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Short[]::new);
751
752            return rec;
753        }
754
755        private static RECORD<Byte, Stream<Byte>> getBYTEStreamRec(
756                byte defaultValue, int FLAGS, Function<String, Byte> optionalUserParser,
757                boolean primitiveOrBoxedOutput1DArray
758            )
759        {
760            RECORD<Byte, Stream<Byte>> rec = new RECORD<>(
761                defaultValue,
762                FLAGS,
763                Byte.class,                 // Class of the Stream.Builder "accept" Parameter
764                ReadArrJSON::byteTypePred,  // Checks the JsonNumber retrieved
765                StringParse::isByte,        // String-tester (for parsing number-strings)
766                Byte::parseByte,            // default-parser (number-string to byte)
767                Number::byteValue,          // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
768                BigDecimal::byteValueExact, // Generates AEX on fail
769                optionalUserParser
770            );
771
772            // Only used by "DimN" Sub-Class.  It builds the 1D arrays.  Since short's do not have
773            // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be
774            // used to dispatch-build *BOTH* a short[] and a Short[]
775
776            rec.array1DGenerator = primitiveOrBoxedOutput1DArray
777                ? rec::array1DGeneratorByte
778                : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Byte[]::new);
779
780            return rec;
781        }
782
783        private static RECORD<Long, Stream<Long>> getLONGStreamRec
784            (long defaultValue, int FLAGS, Function<String, Long> optionalUserParser)
785        {
786            RECORD<Long, Stream<Long>> rec = new RECORD<>(
787                defaultValue,
788                FLAGS,
789                Long.class,                 // Class of the Stream.Builder "accept" Parameter
790                ReadArrJSON::longTypePred,  // Checks the JsonNumber retrieved
791                StringParse::isLong,        // String-tester (for parsing number-strings)
792                Long::parseLong,            // default-parser (number-string to long)
793                Number::longValue,          // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
794                BigDecimal::longValueExact, // Generates AEX on fail
795                optionalUserParser
796            );
797
798            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
799            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON.
800            // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 
801            // primitive "long[]" array (rather than an "Long[]"), "LongStream.toArray" is used
802
803            rec.array1DGenerator = (JsonArray ja) ->
804                jsonArrToBoxedStream(ja, rec).toArray(Long[]::new);
805
806            return rec;
807        }
808
809        private static RECORD<Double, Stream<Double>> getDOUBLEStreamRec
810            (double defaultValue, int FLAGS, Function<String, Double> optionalUserParser)
811        {
812            RECORD<Double, Stream<Double>> rec = new RECORD<>(
813                defaultValue,
814                FLAGS,
815                Double.class,                   // Class of the Stream.Builder "accept" Parameter
816                ReadArrJSON::doubleTypePred,    // Checks the JsonNumber retrieved
817                StringParse::isDouble,          // String-tester (for parsing number-strings)
818                Double::parseDouble,            // default-parser (number-string to double)
819                Number::doubleValue,            // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
820                (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); },
821                optionalUserParser
822            );
823
824            // This is used by the methods in the Nested-Class "DimN" only.  It is a wrapper
825            // for the JsonArray -> JavaArray method.  This is *NOT* used in ReadArrJSON.
826            // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 
827            // primitive "double[]" array (rather than an "Double[]"), "DoubleStream.toArray" is
828            // used
829
830            rec.array1DGenerator = (JsonArray ja) ->
831                jsonArrToBoxedStream(ja, rec).toArray(Double[]::new);
832
833            return rec;
834        }
835
836        private static RECORD<Float, Stream<Float>> getFLOATStreamRec(
837                float defaultValue, int FLAGS, Function<String, Float> optionalUserParser,
838                boolean primitiveOrBoxedOutput1DArray
839            )
840        {
841            RECORD<Float, Stream<Float>> rec = new RECORD<>(
842                defaultValue,
843                FLAGS,
844                Float.class,                // Class of the Stream.Builder "accept" Parameter
845                ReadArrJSON::floatTypePred, // Checks the JsonNumber retrieved
846                StringParse::isDouble,      // String-tester (for parsing number-strings)
847                Float::parseFloat,          // default-parser (number-string to float)
848                Number::floatValue,         // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
849                (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); },
850                optionalUserParser
851            );
852
853            // Only used by "DimN" Sub-Class.  It builds the 1D arrays.  Since short's do not have
854            // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be
855            // used to dispatch-build *BOTH* a short[] and a Short[]
856
857            rec.array1DGenerator = primitiveOrBoxedOutput1DArray
858                ? rec::array1DGeneratorFloat
859                : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Float[]::new);
860
861            return rec;
862        }
863
864        private static RECORD<Boolean, Stream<Boolean>> getBOOLEANStreamRec(
865                boolean defaultValue, int FLAGS, Function<String, Boolean> optionalUserParser,
866                boolean primitiveOrBoxedOutput1DArray
867            )
868        {
869            RECORD<Boolean, Stream<Boolean>> rec = new RECORD<>(
870                defaultValue,
871                FLAGS,
872                Boolean.class,          // Class of the Stream.Builder "accept" Parameter
873                null,                   // Checks the JsonNumber retrieved
874                s -> true,              // String-tester (for parsing number-strings)
875                Boolean::parseBoolean,  // default-parser (number-string to float)
876                null,                   // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
877                null,
878                optionalUserParser
879            );
880
881            // Only used by "DimN" Sub-Class.  It builds the 1D arrays.  Since short's do not have
882            // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be
883            // used to dispatch-build *BOTH* a short[] and a Short[]
884
885            rec.array1DGenerator = primitiveOrBoxedOutput1DArray
886                ? rec::array1DGeneratorBoolean
887                : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Boolean[]::new);
888
889            return rec;
890        }
891
892        private static RECORD<Number, Stream<Number>> getNumberStreamRec
893            (Number defaultValue, int FLAGS, Function<String, Number> optionalUserParser)
894        {
895            RECORD<Number, Stream<Number>> rec = new RECORD<>(
896                defaultValue,
897                FLAGS,
898                Number.class,               // Class of the Stream.Builder "accept" Parameter
899                (JsonNumber jn) -> true,    // Checks the JsonNumber retrieved
900                StringParse::isDouble,      // String-tester (for parsing number-strings)
901                Float::parseFloat,          // default-parser (number-string to float)
902                (Number n) -> n,            // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
903                (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); },
904                optionalUserParser
905            );
906
907            rec.array1DGenerator = (JsonArray ja) ->
908                jsonArrToBoxedStream(ja, rec).toArray(Number[]::new);
909
910            return rec;
911        }
912
913
914        // ****************************************************************************************
915        // ****************************************************************************************
916        // Static RECORD Factory/Builder Methods  --  Other-Streams
917        // ****************************************************************************************
918        // ****************************************************************************************
919
920
921        private static RECORD<String, Stream<String>>
922            getStringStreamRec(String defaultValue, int FLAGS)
923        {
924            RECORD<String, Stream<String>> rec = new RECORD<String, Stream<String>> (
925                defaultValue,
926                FLAGS,
927                String.class,       // Class of the Stream.Builder "accept" Parameter
928                null,               // Checks the JsonNumber retrieved
929                null,               // String-tester (for parsing number-strings)
930                null,               // default-parser (number-string to float)
931                null,               // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
932                null,               // Generates AEX on fail
933                null                // optionalUserParser
934            );
935
936            rec.array1DGenerator = (JsonArray ja) ->
937                strArrayToStreamINTERNAL(ja, rec).toArray(String[]::new);
938
939            return rec;
940        }
941
942        @SuppressWarnings("unchecked") // Array.newInstance returns "Object" not 
943        private static <X> RECORD<X, Stream<X>>
944            getObjectStreamRec(X defaultValue, int FLAGS, Class<X> returnClass)
945        {
946            RECORD<X, Stream<X>> rec = new RECORD<>(
947                defaultValue,
948                FLAGS,
949                returnClass,        // Class of the Stream.Builder "accept" Parameter
950                null,               // Checks the JsonNumber retrieved
951                null,               // String-tester (for parsing number-strings)
952                null,               // default-parser (number-string to float)
953                null,               // numberConverter (JAPPROX_ON_AEX *AND* usual-ans)
954                null,
955                null                // optionalUserParser
956            );
957
958            rec.array1DGenerator = (JsonArray ja) ->
959               objArrayToStreamINTERNAL(ja, rec).toArray
960                   ((int length) -> (X[]) Array.newInstance(returnClass, length));
961
962            return rec;
963        }
964
965
966        // ****************************************************************************************
967        // ****************************************************************************************
968        // Static RECORD Factory/Builder ==> HELPERS FOR THE FACTORY-METHODS
969        // ****************************************************************************************
970        // ****************************************************************************************
971        //
972        // REMEMBER: The 1-D Arrays ==> int[], long[], double[] are built directly from a 
973        //           PrimitiveStream using PrimStream.toArray, they don't need a "helper"
974
975
976        // This method is only used if the input was "Short", so it is actually not "Unchecked"
977        // but the Java-Compiler isn't smart enough to see that.
978        @SuppressWarnings("unchecked")
979        private short[] array1DGeneratorShort(JsonArray ja)
980        {
981            short[] retArrShort = new short[ja.size()];
982
983            return boxedStreamToPrimitiveArray(
984                jsonArrToBoxedStream(ja, (RECORD<Short, Stream<Short>>) this),
985                ja,
986                short.class,
987                (Short s, int i) -> retArrShort[i] = s.shortValue(),
988                retArrShort
989            );
990        }
991
992        // This method is only used if the input was "Byte", so it is actually not "Unchecked"
993        // but the Java-Compiler isn't smart enough to see that.
994        @SuppressWarnings("unchecked")
995        private byte[] array1DGeneratorByte(JsonArray ja)
996        {
997            byte[] retArrByte = new byte[ja.size()];
998
999            return boxedStreamToPrimitiveArray(
1000                jsonArrToBoxedStream(ja, (RECORD<Byte, Stream<Byte>>) this),
1001                ja,
1002                byte.class,
1003                (Byte s, int i) -> retArrByte[i] = s.byteValue(),
1004                retArrByte
1005            );
1006        }
1007
1008        // This method is only used if the input was "Float", so it is actually not "Unchecked"
1009        // but the Java-Compiler isn't smart enough to see that.
1010        @SuppressWarnings("unchecked")
1011        private float[] array1DGeneratorFloat(JsonArray ja)
1012        {
1013            float[] retArrFloat = new float[ja.size()];
1014
1015            return boxedStreamToPrimitiveArray(
1016                jsonArrToBoxedStream(ja, (RECORD<Float, Stream<Float>>) this),
1017                ja,
1018                float.class,
1019                (Float s, int i) -> retArrFloat[i] = s.floatValue(),
1020                retArrFloat
1021            );
1022        }
1023
1024        // This method is only used if the input was "Boolean", so it is actually not "Unchecked"
1025        // but the Java-Compiler isn't smart enough to see that.
1026        @SuppressWarnings("unchecked")
1027        private boolean[] array1DGeneratorBoolean(JsonArray ja)
1028        {
1029            boolean[] retArrBoolean = new boolean[ja.size()];
1030
1031            return boxedStreamToPrimitiveArray(
1032                booleanArrayToBoxedStreamINTERNAL
1033                    (ja, (RECORD<Boolean, Stream<Boolean>>) this),
1034                ja,
1035                boolean.class,
1036                (Boolean s, int i) -> retArrBoolean[i] = s.booleanValue(),
1037                retArrBoolean
1038            );
1039        }
1040    }
1041
1042
1043    // ********************************************************************************************
1044    // ********************************************************************************************
1045    // PRIMARY CONVERTER FOR THREE STREAM FUNCTIONS
1046    // ********************************************************************************************
1047    // ********************************************************************************************
1048    //
1049    // NOTE: There is just no-way to document this damned thing.  *ALL IT IS DOING* is telling you
1050    //       that a Json-Array like [3, 4, 5] maps to a Java-Array like [3, 4, 5].  The extra
1051    //       work is checking for things like ["3", 4, 5] (where the 3 is a String), since this
1052    //       is completely legal in JSON, but not Java.  AND ALSO: [3.0, 4.1, 5.2] can be mapped
1053    //       to [3, 4, 5] - if and only if the FLAGS are properly set by the user...
1054    //
1055    // The whole value of this is the error-checking, and the ability to TIGHTEN AND RELAX the
1056    // requirements.  It makes using a REST-API (which communicates with the outside world using
1057    // JSON), a whole bunch of ONE-LINE statments.  (This HELPS a lot, but it is so AWFUL to look
1058    // at)
1059
1060    /**
1061     * Builds a Primitive-Stream from a {@link JsonArray}
1062     * 
1063     * @param ja The {@link JsonArray}
1064     * @param rec The configurations
1065     * 
1066     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html'
1067     *      DATA-FILE-ID=RARR_PS_JNPAEX>
1068     * 
1069     * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JAAEX>
1070     * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JSPAEX>
1071     * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JTAEX>
1072     */
1073    protected static <T, U> U jsonArrToStream(JsonArray ja, RECORD<T, U> rec)
1074    {
1075        rec.ja = ja;
1076        rec.c.run();    // Construct a new Stream-Builder
1077
1078        int SIZE = ja.size();
1079        JsonValue jv;
1080
1081        for (int i=0; i < SIZE; i++)
1082
1083            switch ((jv = ja.get(i)).getValueType())
1084            {
1085                // javax.json.JsonValue.ValueType.NULL
1086                case NULL:
1087                    if (rec.handlerNull != null) rec.handlerNull.run();
1088                    else throw new JsonNullPrimitiveArrException(ja, i, NUMBER, rec.CLASS);
1089                    break;
1090
1091                // javax.json.JsonValue.ValueType.NUMBER
1092                case NUMBER:
1093
1094                    JsonNumber jn = (JsonNumber) jv;
1095
1096                    // Guaranteed to work properly ==> This is the "definition of RJA_AEX"
1097                    //
1098                    // "numberConverter" is just Number.intValue, longValue, doubleValue
1099                    // Number.intValue(), longValue(), doubleValue() **DO NOT** throw any
1100                    // exceptions.  They round (if necessary), or return MAX_INT, MAX_LONG, etc...
1101                    // (also, only if necessary)
1102
1103                    if (rec.RJA_AEX || rec.jsonNumWillFit.test(jn))
1104                        rec.a.accept(rec.numberConverter.apply(jn.numberValue()));
1105
1106                    else if (rec.handlerAEX != null) rec.handlerAEX.run();
1107
1108                    else throw new JsonArithmeticArrException
1109                        (getAEX(jn, rec.numberConverterExThrow), ja, i, NUMBER, jv, rec.CLASS);
1110
1111                    break;
1112
1113                // javax.json.JsonValue.ValueType.STRING
1114                case STRING: rec.handlerJsonString.accept(jv, i); break;
1115
1116                // javax.json.JsonValue.ValueType.TRUE, FALSE, ARRAY, OBJECT
1117                default:
1118                    if (rec.handlerWrongType != null) rec.handlerWrongType.run();
1119                    else throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS);
1120            }
1121
1122        // Run Stream.Builder.build(); 
1123        return rec.b.get();
1124    }
1125
1126
1127    // ********************************************************************************************
1128    // ********************************************************************************************
1129    // THREE JSON-ARRAY  ==>  JAVA-STREAM METHODS (int-stream, double-stream, long-stream)
1130    // ********************************************************************************************
1131    // ********************************************************************************************
1132
1133
1134    /**
1135     * Convenience Method.
1136     * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)}
1137     * <BR />Passes: Java {@code IntStream} Configurtion-Record
1138     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream
1139     * <BR />For information about the {@link JFlag} parameter, click the method link above.
1140     * 
1141     * <BR /><BR />Producing a standard java {@code int[]} array from an {@code IntStream} is a
1142     * trivial-converstion:
1143     * 
1144     * <DIV CLASS=LOC>{@code
1145     * int[] arr = intArrayToStream(ja, -1, 0, null).toArray();
1146     * }</DIV>
1147     */
1148    public static IntStream intArrayToStream
1149        (JsonArray ja, int defaultValue, int FLAGS, ToIntFunction<String> optionalUserParser)
1150    {
1151        return jsonArrToStream(
1152            ja, RECORD.getIntStreamRec
1153                (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser)
1154        );
1155    }
1156
1157    /**
1158     * Convenience Method.
1159     * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)}
1160     * <BR />Passes: Java {@code LongStream} Configurtion-Record
1161     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream
1162     * <BR />For information about the {@link JFlag} parameter, click the method link above.
1163     * 
1164     * <BR /><BR />Producing a standard java {@code long[]} array from a {@code LongStream} is a
1165     * trivial-converstion:
1166     * 
1167     * <DIV CLASS=LOC>{@code
1168     * long[] arr = longArrayToStream(ja, -1, 0, null).toArray();
1169     * }</DIV>
1170     */
1171    public static LongStream longArrayToStream
1172        (JsonArray ja, long defaultValue, int FLAGS, ToLongFunction<String> optionalUserParser)
1173    {
1174        return jsonArrToStream(
1175            ja, RECORD.getLongStreamRec
1176                (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser)
1177        );
1178    }
1179
1180    /**
1181     * Convenience Method.
1182     * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)}
1183     * <BR />Passes: Java {@code DoubleStream} Configurtion-Record
1184     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream
1185     * <BR />For information about the {@link JFlag} parameter, click the method link above.
1186     * 
1187     * <BR /><BR />Producing a standard java {@code double[]} array from a {@code DoubleStream} is
1188     * a trivial-converstion:
1189     * 
1190     * <DIV CLASS=LOC>{@code
1191     * double[] arr = doubleArrayToStream(ja, -1, 0, null).toArray();
1192     * }</DIV>
1193     */
1194    public static DoubleStream doubleArrayToStream
1195        (JsonArray ja, double defaultValue, int FLAGS, ToDoubleFunction<String> optionalUserParser)
1196    {
1197        return jsonArrToStream(
1198            ja, RECORD.getDoubleStreamRec
1199                (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser)
1200        );
1201    }
1202
1203
1204    // ********************************************************************************************
1205    // ********************************************************************************************
1206    // PRIMARY CONVERTER FOR STREAM OF BOXED-TYPES
1207    // ********************************************************************************************
1208    // ********************************************************************************************
1209
1210
1211    /**
1212     * Builds a Stream of Boxed-Type Numbers from a {@link JsonArray}
1213     * @param rec The configurations
1214     * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html'
1215     *      DATA-FILE-ID=RARR_BS_JNPAEX>
1216     * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JAAEX>
1217     * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JSPAEX>
1218     * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JTAEX>
1219     */
1220    protected static <T, U> U jsonArrToBoxedStream(JsonArray ja, RECORD<T, U> rec)
1221    {
1222        rec.c.run();    // Construct a new Stream-Builder
1223        rec.ja = ja;
1224
1225        int SIZE = ja.size();
1226        JsonValue jv;
1227
1228        for (int i=0; i < SIZE; i++)
1229
1230            switch ((jv = ja.get(i)).getValueType())
1231            {
1232                // javax.json.JsonValue.ValueType.NULL
1233                case NULL: rec.handlerNull.run(); break;
1234
1235                // javax.json.JsonValue.ValueType.NUMBER
1236                case NUMBER:
1237
1238                    JsonNumber jn = (JsonNumber) jv;
1239
1240                    // Guaranteed to work properly ==> This is the "definition of RJA_AEX"
1241                    //
1242                    // Number.intValue(), longValue(), doubleValue() **DO NOT** throw any
1243                    // exceptions.  They round (if necessary), or return MAX_INT, MAX_LONG, etc...
1244                    // (also, only if necessary)
1245
1246                    if (rec.RJA_AEX ||  rec.jsonNumWillFit.test(jn))
1247                        rec.a.accept(rec.numberConverter.apply(jn.numberValue()));
1248
1249                    else if (rec.handlerAEX != null) rec.handlerAEX.run();
1250
1251                    else throw new JsonArithmeticArrException
1252                        (getAEX(jn, rec.numberConverterExThrow), ja, i, NUMBER, jv, rec.CLASS);
1253
1254                    break;
1255
1256                // javax.json.JsonValue.ValueType.STRING
1257                case STRING: rec.handlerJsonString.accept(jv, i); break;
1258
1259                // OBJECT, ARRAY, TRUE, FALSE
1260                default:
1261                    if (rec.handlerWrongType != null) rec.handlerWrongType.run();
1262                    else throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS);
1263            }
1264
1265        // Run Stream.Builder.build()
1266        return rec.b.get();
1267    }
1268
1269
1270    // ********************************************************************************************
1271    // ********************************************************************************************
1272    // Json-Array to Java Arrays of Primitives
1273    // ********************************************************************************************
1274    // ********************************************************************************************
1275
1276
1277    /**
1278     * Converts a Java Boxed Stream to a Primitive Array.
1279     * @param <T> The generic-type of the {@code java.util.stream.Stream}
1280     * @param <U> The returned primitive-array type
1281     * @param boxedStream A Java Boxed Stream
1282     * @param arrayBuilder A consumer which inserts a Boxed-Number into the Primitive-Array
1283     * @param ja The {@link JsonArray} that generated the Boxed-Stream.  Needed for error-output
1284     * @param returnClass The {@code java.lang.Class} (generic-type parameter) for the
1285     * {@code Stream}.  In other words, the {@code Class} for type-parameter {@code <T>}.
1286     * This is only needed if there is an exception, for proper &amp; readable error-reporting.
1287     */
1288    protected static <T, U> U boxedStreamToPrimitiveArray(
1289            Stream<T>           boxedStream,
1290            JsonArray           ja,
1291            Class<T>            returnClass,
1292            ObjIntConsumer<T>   arrayBuilder,
1293            U                   retArr
1294        )
1295    {
1296        // Since the array-index is used inside of a LAMBDA, this "EffectivelyFinal" counter
1297        // class becomes necessary.
1298
1299        Counter counter = new Counter(-1);
1300
1301        // Don't forget, Stream's are not guaranteed to be processed in order, unless an
1302        // explicit request is made using something like 'forEachOrdered'
1303
1304        boxedStream.forEachOrdered((T boxedPrimitive) ->
1305        {
1306            int i = counter.addOne();   // "Final, or Effectively Final"
1307
1308            // A Primitive-Array (like int[], long[], boolean[] etc...) may not have null
1309            if (boxedPrimitive == null)
1310                throw new JsonNullPrimitiveArrException(ja, i, NUMBER, returnClass);
1311
1312            // The 'arrayBuilder' just assigns the value to the array[i]
1313            arrayBuilder.accept(boxedPrimitive, i);
1314        });
1315    
1316        return retArr;
1317    }
1318
1319    /**
1320     * Convenience Method.
1321     * <BR />Invokes: {@link #shortArrayToBoxedStream(JsonArray, short, int, Function)}
1322     * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer,
1323     *      Object)}
1324     * <BR />
1325     * <BR />Converts: {@link JsonArray} to {@code Stream<Short>} and then to {@code short[]}
1326     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array
1327     * <BR />
1328     * <BR />For information about using {@code FLAGS}, see:
1329     * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B>
1330     */
1331    public static short[] shortArray
1332        (JsonArray ja, short defaultValue, int FLAGS, ToShortFunction<String> optionalUserParser)
1333    {
1334        short[] retArr = new short[ja.size()];
1335
1336        return boxedStreamToPrimitiveArray(
1337            shortArrayToBoxedStream(
1338                // If there are any "Return null if..." JFlag's, they are eliminated
1339                ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,
1340
1341                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
1342                (optionalUserParser != null)
1343                    ? (String s) -> optionalUserParser.applyAsShort(s)
1344                    : null
1345            ),
1346            ja,
1347            short.class,
1348            (Short s, int i) -> retArr[i] = s.shortValue(),
1349            retArr
1350        );
1351    }
1352
1353    /**
1354     * Convenience Method.
1355     * <BR />Invokes: {@link #byteArrayToBoxedStream(JsonArray, byte, int, Function)}
1356     * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer,
1357     *      Object)}
1358     * <BR />
1359     * <BR />Converts: {@link JsonArray} to {@code Stream<Byte>} and then to {@code byte[]}
1360     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array
1361     * <BR />
1362     * <BR />For information about using {@code FLAGS}, see:
1363     * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B>
1364     */
1365    public static byte[] byteArray
1366        (JsonArray ja, byte defaultValue, int FLAGS, ToByteFunction<String> optionalUserParser)
1367    {
1368        byte[] retArr = new byte[ja.size()];
1369
1370        return boxedStreamToPrimitiveArray(
1371            byteArrayToBoxedStream(
1372                // If there are any "Return null if..." JFlag's, they are eliminated
1373                ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,
1374
1375                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
1376                (optionalUserParser != null)
1377                    ? (String s) -> optionalUserParser.applyAsByte(s)
1378                    : null
1379            ),
1380            ja,
1381            byte.class,
1382            (Byte s, int i) -> retArr[i] = s.byteValue(),
1383            retArr
1384        );
1385    }
1386
1387    /**
1388     * Convenience Method.
1389     * <BR />Invokes: {@link #floatArrayToBoxedStream(JsonArray, float, int, Function)}
1390     * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer,
1391     *      Object)}
1392     * <BR />
1393     * <BR />Converts: {@link JsonArray} to {@code Stream<Float>} and then to {@code float[]}
1394     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array
1395     * <BR />
1396     * <BR />For information about using {@code FLAGS}, see:
1397     * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B>
1398     */
1399    public static float[] floatArray
1400        (JsonArray ja, float defaultValue, int FLAGS, ToFloatFunction<String> optionalUserParser)
1401    {
1402        float[] retArr = new float[ja.size()];
1403
1404        return boxedStreamToPrimitiveArray(
1405            floatArrayToBoxedStream(
1406                // If there are any "Return null if..." JFlag's, they are eliminated
1407                ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,
1408
1409                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
1410                (optionalUserParser != null)
1411                    ? (String s) -> optionalUserParser.applyAsFloat(s)
1412                    : null
1413            ),
1414            ja,
1415            float.class,
1416            (Float s, int i) -> retArr[i] = s.floatValue(),
1417            retArr
1418        );
1419    }
1420
1421    /**
1422     * Convenience Method.
1423     * <BR />Invokes: {@link #booleanArrayToBoxedStream(JsonArray, boolean, int, Function)}
1424     * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer,
1425     *      Object)}
1426     * <BR />
1427     * <BR />Converts: {@link JsonArray} to {@code Stream<Boolean>} and then to {@code boolean[]}
1428     * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array
1429     * <BR />
1430     * <BR />For information about using {@code FLAGS}, see:
1431     * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B>
1432     */
1433    public static boolean[] booleanArray(
1434            JsonArray ja, boolean defaultValue, int FLAGS,
1435            Predicate<String> optionalUserParser
1436        )
1437    {
1438        boolean[] retArr = new boolean[ja.size()];
1439
1440        return boxedStreamToPrimitiveArray(
1441            booleanArrayToBoxedStream(
1442                // If there are any "Return null if...", they are eliminated
1443                ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,
1444
1445                // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null!
1446                (optionalUserParser != null) ? (String s) -> optionalUserParser.test(s) : null
1447            ),
1448            ja,
1449            boolean.class,
1450            (Boolean s, int i) -> retArr[i] = s.booleanValue(),
1451            retArr
1452        );
1453    }
1454
1455
1456    // ********************************************************************************************
1457    // ********************************************************************************************
1458    // Json-Array to Stream of Boxed-Number Types
1459    // ********************************************************************************************
1460    // ********************************************************************************************
1461
1462
1463    /**
1464     * Convenience Method.
1465     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1466     * <BR />Fills in Configuration Record for Integer-Retrieval
1467     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1468     * <BR />
1469     * <BR />Producing a Boxed-Integer Array from this Method is as Follows:
1470     * <DIV CLASS=LOC>{@code
1471     * Integer[] arr = integerArrayToBoxedStream(ja, -1, 0 null).toArray(Integer[]::new);
1472     * }</DIV>
1473     */
1474    public static Stream<Integer> integerArrayToBoxedStream
1475        (JsonArray ja, int defaultValue, int FLAGS, Function<String, Integer> optionalUserParser)
1476    {
1477        return jsonArrToBoxedStream
1478            (ja, RECORD.getINTEGERStreamRec(defaultValue, FLAGS, optionalUserParser));
1479    }
1480
1481    /**
1482     * Convenience Method.
1483     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1484     * <BR />Fills in Configuration Record for Short-Retrieval
1485     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1486     * <BR />
1487     * <BR />Producing a Boxed-Short Array from this Method is as Follows:
1488     * <DIV CLASS=LOC>{@code
1489     * Short[] arr = shortArrayToBoxedStream(ja, -1, 0 null).toArray(Short[]::new);
1490     * }</DIV>
1491     */
1492    public static Stream<Short> shortArrayToBoxedStream
1493        (JsonArray ja, short defaultValue, int FLAGS, Function<String, Short> optionalUserParser)
1494    {
1495        return jsonArrToBoxedStream
1496            (ja, RECORD.getSHORTStreamRec(defaultValue, FLAGS, optionalUserParser, false));
1497    }
1498
1499    /**
1500     * Convenience Method.
1501     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1502     * <BR />Fills in Configuration Record for Byte-Retrieval
1503     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1504     * <BR />
1505     * <BR />Producing a Boxed-Byte Array from this Method is as Follows:
1506     * <DIV CLASS=LOC>{@code
1507     * Byte[] arr = byteArrayToBoxedStream(ja, -1, 0 null).toArray(Byte[]::new);
1508     * }</DIV>
1509     */
1510    public static Stream<Byte> byteArrayToBoxedStream
1511        (JsonArray ja, byte defaultValue, int FLAGS, Function<String, Byte> optionalUserParser)
1512    {
1513        return jsonArrToBoxedStream
1514            (ja, RECORD.getBYTEStreamRec(defaultValue, FLAGS, optionalUserParser, false));
1515    }
1516
1517    /**
1518     * Convenience Method.
1519     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1520     * <BR />Fills in Configuration Record for Long-Retrieval
1521     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1522     * <BR />
1523     * <BR />Producing a Boxed-Long Array from this Method is as Follows:
1524     * <DIV CLASS=LOC>{@code
1525     * Long[] arr = longArrayToBoxedStream(ja, -1, 0 null).toArray(Long[]::new);
1526     * }</DIV>
1527     */
1528    public static Stream<Long> longArrayToBoxedStream
1529        (JsonArray ja, long defaultValue, int FLAGS, Function<String, Long> optionalUserParser)
1530    {
1531        return jsonArrToBoxedStream
1532            (ja, RECORD.getLONGStreamRec(defaultValue, FLAGS, optionalUserParser));
1533    }
1534
1535    /**
1536     * Convenience Method.
1537     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1538     * <BR />Fills in Configuration Record for Double-Retrieval
1539     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1540     * <BR />
1541     * <BR />Producing a Boxed-Double Array from this Method is as Follows:
1542     * <DIV CLASS=LOC>{@code
1543     * Double[] arr = doubleArrayToBoxedStream(ja, -1, 0 null).toArray(Double[]::new);
1544     * }</DIV>
1545     */
1546    public static Stream<Double> doubleArrayToBoxedStream
1547        (JsonArray ja, double defaultValue, int FLAGS, Function<String, Double> optionalUserParser)
1548    {
1549        return jsonArrToBoxedStream
1550            (ja, RECORD.getDOUBLEStreamRec(defaultValue, FLAGS, optionalUserParser));
1551    }
1552
1553    /**
1554     * Convenience Method.
1555     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1556     * <BR />Fills in Configuration Record for Float-Retrieval
1557     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1558     * <BR />
1559     * <BR />Producing a Boxed-Float Array from this Method is as Follows:
1560     * <DIV CLASS=LOC>{@code
1561     * Float[] arr = floatArrayToBoxedStream(ja, -1, 0 null).toArray(Float[]::new);
1562     * }</DIV>
1563     */
1564    public static Stream<Float> floatArrayToBoxedStream
1565        (JsonArray ja, float defaultValue, int FLAGS, Function<String, Float> optionalUserParser)
1566    {
1567        return jsonArrToBoxedStream
1568            (ja, RECORD.getFLOATStreamRec(defaultValue, FLAGS, optionalUserParser, false));
1569    }
1570
1571    /**
1572     * Convenience Method.
1573     * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)}
1574     * <BR />Fills in Configuration Record for Number-Retrieval
1575     * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above.
1576     * <BR />
1577     * <BR />Producing a Boxed-Number Array from this Method is as Follows:
1578     * <DIV CLASS=LOC>{@code
1579     * Number[] arr = numberArrayToBoxedStream(ja, -1, 0 null).toArray(Number[]::new);
1580     * }</DIV>
1581     */
1582    public static Stream<Number> numberArrayToBoxedStream
1583        (JsonArray ja, Number defaultValue, int FLAGS, Function<String, Number> optionalUserParser)
1584    {
1585        return jsonArrToBoxedStream
1586            (ja, RECORD.getNumberStreamRec(defaultValue, FLAGS, optionalUserParser));
1587    }
1588
1589
1590    // ********************************************************************************************
1591    // ********************************************************************************************
1592    // More Types
1593    // ********************************************************************************************
1594    // ********************************************************************************************
1595
1596
1597    /**
1598     * Converts a {@link JsonArray} into a {@code Stream<String>}.  A Java {@code Stream<String>}
1599     * is easily converted to a {@code String[]}-Array via a call to:
1600     * 
1601     * <DIV CLASS=LOC>{@code
1602     * String[] sArr = strArrayToStream(myJsonArray, null, 0).toArray(String[]::new);
1603     * }</DIV>
1604     * 
1605     * @param ja Any {@code JsonArray}, but preferrably one which contains instances of
1606     * {@link JsonString}
1607     * 
1608     * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be
1609     * inserted into the output-array when error cases occur at particular array-index locations.
1610     * 
1611     * @param FLAGS Optional flags.  See {@link JFlag} for details.
1612     * 
1613     * @return A Java {@code Stream<String>}.
1614     */
1615    public static Stream<String> strArrayToStream(JsonArray ja, String defaultValue, int FLAGS)
1616    { return strArrayToStreamINTERNAL(ja, RECORD.getStringStreamRec(defaultValue, FLAGS)); }
1617
1618    private static Stream<String> strArrayToStreamINTERNAL
1619        (JsonArray ja, RECORD<String, Stream<String>> rec)
1620    {
1621        int         SIZE    = ja.size();
1622        JsonValue   jv      = null;
1623
1624        rec.c.run();    // Construct a new Stream-Builder
1625        rec.ja = ja;
1626
1627        for (int i=0; i < SIZE; i++)
1628
1629            switch ((jv = ja.get(i)).getValueType())
1630            {
1631                // javax.json.JsonValue.ValueType.NULL
1632                case NULL: rec.handlerNull.run(); break;
1633
1634                // javax.json.JsonValue.ValueType.STRING
1635                case STRING: rec.a.accept(((JsonString) jv).getString()); break;
1636
1637                // OBJECT, ARRAY, TRUE, FALSE, NUMBER
1638                default:
1639
1640                    if (rec.RTS_WT) rec.a.accept(jv.toString());
1641
1642                    else if (rec.handlerWrongType != null) rec.handlerWrongType.run();
1643
1644                    else throw new JsonTypeArrException(ja, i, STRING, jv, String.class);
1645            }
1646
1647        // Run Stream.Builder.build()
1648        return rec.b.get();
1649    }
1650
1651    /**
1652     * Converts a {@link JsonArray} into a {@code Stream<Boolean>}.  A Java {@code Stream<Boolean>}
1653     * is easily converted to a {@code Boolean[]}-Array via a call to the lines below.  Note that
1654     * in this example, the return array is an array of {@code Boolean} objects; it is not a
1655     * primitive {@code boolean[]} array.  (To parse into a primitive array, use
1656     * {@link #booleanArray(JsonArray, boolean, int, Predicate)})
1657     * 
1658     * <DIV CLASS=LOC>{@code
1659     * Boolean[] bArr = booleanArrayToBoxedStream(myJsonArray, false, 0, null)
1660     *      .toArray(Boolean[]::new);
1661     * }</DIV>
1662     * 
1663     * @param ja Any {@code JsonArray}, but preferrably one which contains instances of
1664     * {@link JsonValue#TRUE} or {@link JsonValue#FALSE}
1665     * 
1666     * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be
1667     * inserted into the output-array when error cases occur at particular array-index locations.
1668     * 
1669     * @param FLAGS Optional flags.  See {@link JFlag} for details.
1670     * 
1671     * @param optionalUserParser If the appropriate flags are set, if a {@link JsonString} is
1672     * encountered while processing the {@code JsonArray}, an attempt to parse the {@code String}
1673     * into a {@code Boolean} will be made using this {@code String}-parser.
1674     * 
1675     * @return A Java {@code Stream<Boolean>}.
1676     */
1677    public static Stream<Boolean> booleanArrayToBoxedStream(
1678            JsonArray ja, boolean defaultValue, int FLAGS,
1679            Function<String, Boolean> optionalUserParser
1680        )
1681    {
1682        return booleanArrayToBoxedStreamINTERNAL(
1683            ja,
1684            RECORD.getBOOLEANStreamRec
1685                (defaultValue, FLAGS, optionalUserParser, false)
1686        );
1687    }
1688
1689    private static Stream<Boolean> booleanArrayToBoxedStreamINTERNAL
1690        (JsonArray ja, RECORD<Boolean, Stream<Boolean>> rec)
1691    {
1692        int         SIZE    = ja.size();
1693        JsonValue   jv      = null;
1694
1695        rec.c.run();    // Construct a new Stream-Builder
1696        rec.ja = ja;
1697
1698        for (int i=0; i < SIZE; i++)
1699
1700            switch ((jv = ja.get(i)).getValueType())
1701            {
1702                case NULL:      rec.handlerNull.run(); break;
1703                case TRUE:      rec.a.accept(true); break;
1704                case FALSE:     rec.a.accept(false); break;
1705                case STRING:    rec.handlerJsonString.accept(jv, i); break;
1706
1707                // javax.json.JsonValue.ValueType.NUMBER, OBJECT, ARRAY
1708                default:
1709                    if (rec.handlerWrongType != null) rec.handlerWrongType.run();
1710                    else throw new JsonTypeArrException(ja, i, TRUE, jv, Boolean.class);
1711            }
1712
1713        // Run Stream.Builder.build()
1714        return rec.b.get();
1715    }
1716
1717    /**
1718     * Converts a {@link JsonArray} into a {@code Stream<T>}.  A Java {@code Stream<T>}
1719     * is easily converted to a {@code T[]}-Array via a call to the line below. 
1720     * 
1721     * <DIV CLASS=LOC>{@code
1722     * MyClass[] bArr = objArrayToStream(myJsonArray, null, 0, MyClass.class)
1723     *      .toArray(MyClass[]::new);
1724     * }</DIV>
1725     * 
1726     * @param <T> This is the 'type' of the array being built.  If there were a class, for example,
1727     * named class {@code 'Automobile'}, the value passed to parameter {@code 'returnClass'} would
1728     * simply be {@code Automobile.class}.
1729     * 
1730     * @param ja Any {@code JsonArray}, but preferrably one which contains instances of
1731     * {@link JsonValue#TRUE} or {@link JsonValue#FALSE}
1732     * 
1733     * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be
1734     * inserted into the output-array when error cases occur at particular array-index locations.
1735     * 
1736     * @param FLAGS Optional flags.  See {@link JFlag} for details.
1737     * 
1738     * @param returnClass The {@code java.lang.Class} of the Object being built
1739     * 
1740     * @return A Java {@code Stream<T>}.
1741     */
1742    public static <T> Stream<T> objArrayToStream
1743        (JsonArray ja, T defaultValue, int FLAGS, Class<T> returnClass)
1744    {
1745        return objArrayToStreamINTERNAL
1746            (ja, RECORD.getObjectStreamRec(defaultValue, FLAGS, returnClass));
1747    }
1748
1749    private static <T> Stream<T> objArrayToStreamINTERNAL
1750        (JsonArray ja, RECORD<T, Stream<T>> rec)
1751    {
1752        int                     SIZE    = ja.size();
1753        JsonValue               jv      = null;
1754
1755        rec.c.run();    // Construct a new Stream-Builder
1756        rec.ja = ja;
1757
1758        for (int i=0; i < SIZE; i++)
1759
1760            switch ((jv = ja.get(i)).getValueType())
1761            {
1762                // javax.json.JsonValue.ValueType.NULL
1763                case NULL:
1764                    rec.handlerNull.run();
1765                    break;
1766
1767                // javax.json.JsonValue.ValueType.OBJECT
1768                case OBJECT:
1769                    rec.a.accept(ReadJSON.getObject(((JsonObject) jv), rec.CLASS));
1770                    break;
1771
1772                // javax.json.JsonValue.ValueType.NUMBER, STRING, TRUE, FALSE, ARRAY
1773                default:
1774                    if (rec.handlerWrongType != null) rec.handlerWrongType.run();
1775                    else throw new JsonTypeArrException(ja, i, TRUE, jv, rec.CLASS);
1776            }
1777
1778        // Run Stream.Builder.build()
1779        return rec.b.get();
1780    }
1781
1782    /**
1783     * Parses Multi-Dimensional JSON Array's into Multi-Dimensional Java Array's.
1784     * 
1785     * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE>
1786     * <EMBED CLASS='external-html' DATA-FILE-ID=READ_ARR_JDIMN>
1787     *
1788     * @see Json
1789     * @see JsonArray
1790     */
1791    @Torello.JavaDoc.StaticFunctional
1792    @Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI")
1793    public static class DimN
1794    {
1795        private DimN() { }
1796
1797        /**
1798         * Check user input, and throws exceptions if the array-class has not been properly
1799         * chosen.
1800         * @param retArrClass This must be a primitive-array class, possibly of multiple dimensions
1801         * 
1802         * @param rootClass The expected "root class".  For {@code int[][].class}, the root class
1803         * would be {@code int.class}.
1804         * 
1805         * @return Parameter {@code retArrClass} is the return value of this checker method
1806         * 
1807         * @throws IllegalArgumentExcetion If parameter {@code retArrClass}:
1808         * <BR /><BR /><OL CLASS=JDOL>
1809         * <LI>If calling {@code retArrClass.isArray()} returns {@code FALSE}</LI>
1810         * <LI>If the root-array type is not the appropriate type for the method that was called
1811         *      </LI>
1812         * </OL>
1813         */
1814        private static <T> Class<T> CHECK_ARRAY_CLASS(Class<T> retArrClass, Class<?> rootClass)
1815        {
1816            if (! retArrClass.isArray()) throw new IllegalArgumentException(
1817                "The class you have passed to parameter 'retArrClass' " +
1818                "[" + retArrClass.getSimpleName() + "], is not an array"
1819            );
1820
1821            Class<?> componentClass = retArrClass.getComponentType();
1822
1823            while (componentClass.isArray()) componentClass = componentClass.getComponentType();
1824
1825            if (! rootClass.equals(componentClass)) throw new IllegalArgumentException(
1826                "The class you have passed to parameter 'retArrClass' " +
1827                "[" + retArrClass.getSimpleName() + "], is not a(n) " +
1828                rootClass.getSimpleName() + "-array."
1829            );
1830
1831            return retArrClass;
1832        }
1833
1834        private static Class<?> GET_ARRAY_BASE_COMPONENT_CLASS_AND_CHECK
1835            (Class<?> retArrClass, Object defaultValue)
1836        {
1837            if (! retArrClass.isArray()) throw new IllegalArgumentException(
1838                "The class you have passed to parameter 'retArrClass' " +
1839                "[" + retArrClass.getSimpleName() + "], is not an array"
1840            );
1841
1842            Class<?> componentClass = retArrClass.getComponentType();
1843
1844            while (componentClass.isArray()) componentClass = componentClass.getComponentType();
1845
1846            if (    (defaultValue != null)
1847                &&  componentClass.isAssignableFrom(defaultValue.getClass())
1848            )
1849
1850                throw new IllegalArgumentException(
1851                    "The User Provided Default Value of type: "+
1852                    "[" + defaultValue.getClass().getName() + "], cannot be assigned to the " +
1853                    "Component-Type of the Array: " +
1854                    "[" + componentClass.getName() + "]"
1855                );
1856
1857            return componentClass;
1858        }
1859
1860
1861
1862        // ****************************************************************************************
1863        // ****************************************************************************************
1864        // Primitive Multi-Dimensional Array Methods
1865        // ****************************************************************************************
1866        // ****************************************************************************************
1867
1868
1869        /**
1870         * Convenience Method.
1871         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
1872         * <BR />Passes: {@code int} Configuration-RECORD
1873         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
1874         * <BR />
1875         * <BR />See link above for more {@link JFlag} explanations.
1876         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code int}-array.
1877         * <BR />(See last <B>"return-type"</B> parameter in example below)
1878         * 
1879         * <DIV CLASS=LOC>{@code
1880         * int[][] arr = ReadArrJSON.DimN.intArr(jsonArray, -1, 0, null, int[][].class);
1881         * }</DIV>
1882         */
1883        public static <T> T intArr(
1884                JsonArray ja, int defaultValue, int FLAGS,
1885                ToIntFunction<String> optionalUserParser, Class<T> retArrClass
1886            )
1887        {
1888            return jsonArrToJavaArr(
1889                ja,
1890                RECORD.getIntStreamRec
1891                    (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser),
1892                CHECK_ARRAY_CLASS(retArrClass, int.class)
1893            );
1894        }
1895
1896        /**
1897         * Convenience Method.
1898         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
1899         * <BR />Passes: {@code long} Configuration-RECORD
1900         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
1901         * <BR />
1902         * <BR />See link above for more {@link JFlag} explanations.
1903         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code long}-array.
1904         * <BR />(See last <B>"return-type"</B> parameter in example below)
1905         * 
1906         * <DIV CLASS=LOC>{@code
1907         * long[][] arr = ReadArrJSON.DimN.longArr(jsonArray, -1, 0, null, long[][].class);
1908         * }</DIV>
1909         */
1910        public static <T> T longArr(
1911                JsonArray ja, long defaultValue, int FLAGS,
1912                ToLongFunction<String> optionalUserParser, Class<T> retArrClass
1913            )
1914        {
1915            return jsonArrToJavaArr(
1916                ja,
1917                RECORD.getLongStreamRec
1918                    (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser),
1919                CHECK_ARRAY_CLASS(retArrClass, long.class)
1920            );
1921        }
1922
1923        /**
1924         * Convenience Method.
1925         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
1926         * <BR />Passes: {@code double} Configuration-RECORD
1927         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
1928         * <BR />
1929         * <BR />See link above for more {@link JFlag} explanations.
1930         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code double}-array.
1931         * <BR />(See last <B>"return-type"</B> parameter in example below)
1932         * 
1933         * <DIV CLASS=LOC>{@code
1934         * double[][] arr = ReadArrJSON.DimN.doubleArr(jsonArray, -1, 0, null, double[][].class);
1935         * }</DIV>
1936         */
1937        public static <T> T doubleArr(
1938                JsonArray ja, double defaultValue, int FLAGS,
1939                ToDoubleFunction<String> optionalUserParser, Class<T> retArrClass
1940            )
1941        {
1942            return jsonArrToJavaArr(
1943                ja,
1944                RECORD.getDoubleStreamRec
1945                    (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser),
1946                CHECK_ARRAY_CLASS(retArrClass, double.class)
1947            );
1948        }
1949
1950        /**
1951         * Convenience Method.
1952         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
1953         * <BR />Passes: {@code short} Configuration-RECORD
1954         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
1955         * <BR />
1956         * <BR />See link above for more {@link JFlag} explanations.
1957         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code short}-array.
1958         * <BR />(See last <B>"return-type"</B> parameter in example below)
1959         * 
1960         * <DIV CLASS=LOC>{@code
1961         * short[][] arr = ReadArrJSON.DimN.shortArr(jsonArray, -1, 0, null, short[][].class);
1962         * }</DIV>
1963         */
1964        public static <T> T shortArr(
1965                JsonArray ja, short defaultValue, int FLAGS,
1966                ToShortFunction<String> optionalUserParser, Class<T> retArrClass
1967            )
1968        {
1969            return jsonArrToJavaArr(
1970                ja,
1971                RECORD.getSHORTStreamRec(
1972                    defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,    
1973                    (optionalUserParser != null)
1974                        ? (String s) -> optionalUserParser.applyAsShort(s)
1975                        : null,
1976                    true
1977                ),
1978                CHECK_ARRAY_CLASS(retArrClass, short.class)
1979            );
1980        }
1981
1982        /**
1983         * Convenience Method.
1984         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
1985         * <BR />Passes: {@code byte} Configuration-RECORD
1986         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
1987         * <BR />
1988         * <BR />See link above for more {@link JFlag} explanations.
1989         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code byte}-array.
1990         * <BR />(See last <B>"return-type"</B> parameter in example below)
1991         * 
1992         * <DIV CLASS=LOC>{@code
1993         * byte[][] arr = ReadArrJSON.DimN.byteArr(jsonArray, -1, 0, null, byte[][].class);
1994         * }</DIV>
1995         */
1996        public static <T> T byteArr(
1997                JsonArray ja, byte defaultValue, int FLAGS,
1998                ToByteFunction<String> optionalUserParser, Class<T> retArrClass
1999            )
2000        {
2001            return jsonArrToJavaArr(
2002                ja,
2003                RECORD.getBYTEStreamRec(
2004                    defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,    
2005                    (optionalUserParser != null)
2006                        ? (String s) -> optionalUserParser.applyAsByte(s)
2007                        : null,
2008                    true
2009                ),
2010                CHECK_ARRAY_CLASS(retArrClass, byte.class)
2011            );
2012        }
2013
2014        /**
2015         * Convenience Method.
2016         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2017         * <BR />Passes: {@code float} Configuration-RECORD
2018         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
2019         * <BR />
2020         * <BR />See link above for more {@link JFlag} explanations.
2021         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code float}-array.
2022         * <BR />(See last <B>"return-type"</B> parameter in example below)
2023         * 
2024         * <DIV CLASS=LOC>{@code
2025         * float[][] arr = ReadArrJSON.DimN.floatArr(jsonArray, -1, 0, null, float[][].class);
2026         * }</DIV>
2027         */
2028        public static <T> T floatArr(
2029                JsonArray ja, float defaultValue, int FLAGS,
2030                ToFloatFunction<String> optionalUserParser, Class<T> retArrClass
2031            )
2032        {
2033            return jsonArrToJavaArr(
2034                ja,
2035                RECORD.getFLOATStreamRec(
2036                    defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,    
2037                    (optionalUserParser != null)
2038                        ? (String s) -> optionalUserParser.applyAsFloat(s)
2039                        : null,
2040                    true
2041                ),
2042                CHECK_ARRAY_CLASS(retArrClass, float.class)
2043            );
2044        }
2045
2046        /**
2047         * Convenience Method.
2048         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2049         * <BR />Passes: {@code boolean} Configuration-RECORD
2050         * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry
2051         * <BR />
2052         * <BR />See link above for more {@link JFlag} explanations.
2053         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code boolean}-array.
2054         * <BR />(See last <B>"return-type"</B> parameter in example below)
2055         * 
2056         * <DIV CLASS=LOC>{@code
2057         * boolean[][] arr = ReadArrJSON.DimN.booleanArr
2058         *      (jsonArray, -1, 0, null, boolean[][].class);
2059         * }</DIV>
2060         */
2061        public static <T> T booleanArr(
2062                JsonArray ja, boolean defaultValue, int FLAGS,
2063                Predicate<String> optionalUserParser, Class<T> retArrClass
2064            )
2065        {
2066            return jsonArrToJavaArr(
2067                ja,
2068                RECORD.getBOOLEANStreamRec(
2069                    defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS,    
2070                    (optionalUserParser != null)
2071                        ? (String s) -> optionalUserParser.test(s)
2072                        : null,
2073                    true
2074                ),
2075                CHECK_ARRAY_CLASS(retArrClass, boolean.class)
2076            );
2077        }
2078
2079
2080        // ****************************************************************************************
2081        // ****************************************************************************************
2082        // Boxed-Primitive Multi-Dimensional Array Methods
2083        // ****************************************************************************************
2084        // ****************************************************************************************
2085
2086
2087        /**
2088         * Convenience Method.
2089         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2090         * <BR />Passes: {@code Integer} Configuration-RECORD
2091         * <BR />See link above for more {@link JFlag} explanations.
2092         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Integer}-array.
2093         * <BR />(See last <B>"return-type"</B> parameter in example below)
2094         * 
2095         * <DIV CLASS=LOC>{@code
2096         * Integer[][] arr = ReadArrJSON.DimN.arrINTEGER(jsonArray, -1, 0, null, Integer[][].class);
2097         * }</DIV>
2098         */
2099        public static <T> T arrINTEGER(
2100                JsonArray ja, int defaultValue, int FLAGS,
2101                Function<String, Integer> optionalUserParser, Class<T> retArrClass
2102            )
2103        {
2104            return jsonArrToJavaArr(
2105                ja,
2106                RECORD.getINTEGERStreamRec(defaultValue, FLAGS, optionalUserParser),
2107                CHECK_ARRAY_CLASS(retArrClass, Integer.class)
2108            );
2109        }
2110
2111        /**
2112         * Convenience Method.
2113         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2114         * <BR />Passes: {@code Long} Configuration-RECORD
2115         * <BR />See link above for more {@link JFlag} explanations.
2116         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Long}-array.
2117         * <BR />(See last <B>"return-type"</B> parameter in example below)
2118         * 
2119         * <DIV CLASS=LOC>{@code
2120         * Long[][] arr = ReadArrJSON.DimN.arrLONG(jsonArray, -1, 0, null, Long[][].class);
2121         * }</DIV>
2122         */
2123        public static <T> T arrLONG(
2124                JsonArray ja, long defaultValue, int FLAGS,
2125                Function<String, Long> optionalUserParser, Class<T> retArrClass
2126            )
2127        {
2128            return jsonArrToJavaArr(
2129                ja,
2130                RECORD.getLONGStreamRec(defaultValue, FLAGS, optionalUserParser),
2131                CHECK_ARRAY_CLASS(retArrClass, Long.class)
2132            );
2133        }
2134
2135        /**
2136         * Convenience Method.
2137         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2138         * <BR />Passes: {@code Double} Configuration-RECORD
2139         * <BR />See link above for more {@link JFlag} explanations.
2140         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Double}-array.
2141         * <BR />(See last <B>"return-type"</B> parameter in example below)
2142         * 
2143         * <DIV CLASS=LOC>{@code
2144         * Double[][] arr = ReadArrJSON.DimN.arrDOUBLE(jsonArray, -1, 0, null, Double[][].class);
2145         * }</DIV>
2146         */
2147        public static <T> T arrDOUBLE(
2148                JsonArray ja, double defaultValue, int FLAGS,
2149                Function<String, Double> optionalUserParser, Class<T> retArrClass
2150            )
2151        {
2152            return jsonArrToJavaArr(
2153                ja,
2154                RECORD.getDOUBLEStreamRec(defaultValue, FLAGS, optionalUserParser),
2155                CHECK_ARRAY_CLASS(retArrClass, Double.class)
2156            );
2157        }
2158
2159        /**
2160         * Convenience Method.
2161         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2162         * <BR />Passes: {@code Short} Configuration-RECORD
2163         * <BR />See link above for more {@link JFlag} explanations.
2164         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Short}-array.
2165         * <BR />(See last <B>"return-type"</B> parameter in example below)
2166         * 
2167         * <DIV CLASS=LOC>{@code
2168         * Short[][] arr = ReadArrJSON.DimN.arrSHORT(jsonArray, -1, 0, null, Short[][].class);
2169         * }</DIV>
2170         */
2171        public static <T> T arrSHORT(
2172                JsonArray ja, short defaultValue, int FLAGS,
2173                Function<String, Short> optionalUserParser, Class<T> retArrClass
2174            )
2175        {
2176            return jsonArrToJavaArr(
2177                ja,
2178                RECORD.getSHORTStreamRec(defaultValue, FLAGS, optionalUserParser, true),
2179                CHECK_ARRAY_CLASS(retArrClass, Short.class)
2180            );
2181        }
2182
2183        /**
2184         * Convenience Method.
2185         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2186         * <BR />Passes: {@code Byte} Configuration-RECORD
2187         * <BR />See link above for more {@link JFlag} explanations.
2188         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Byte}-array.
2189         * <BR />(See last <B>"return-type"</B> parameter in example below)
2190         * 
2191         * <DIV CLASS=LOC>{@code
2192         * Byte[][] arr = ReadArrJSON.DimN.arrBYTE(jsonArray, -1, 0, null, Byte[][].class);
2193         * }</DIV>
2194         */
2195        public static <T> T arrBYTE(
2196                JsonArray ja, byte defaultValue, int FLAGS,
2197                Function<String, Byte> optionalUserParser, Class<T> retArrClass
2198            )
2199        {
2200            return jsonArrToJavaArr(
2201                ja,
2202                RECORD.getBYTEStreamRec(defaultValue, FLAGS, optionalUserParser, true),
2203                CHECK_ARRAY_CLASS(retArrClass, Byte.class)
2204            );
2205        }
2206
2207        /**
2208         * Convenience Method.
2209         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2210         * <BR />Passes: {@code Float} Configuration-RECORD
2211         * <BR />See link above for more {@link JFlag} explanations.
2212         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Float}-array.
2213         * <BR />(See last <B>"return-type"</B> parameter in example below)
2214         * 
2215         * <DIV CLASS=LOC>{@code
2216         * Float[][] arr = ReadArrJSON.DimN.arrFLOAT(jsonArray, -1, 0, null, Float[][].class);
2217         * }</DIV>
2218         */
2219        public static <T> T arrFLOAT(
2220                JsonArray ja, float defaultValue, int FLAGS,
2221                Function<String, Float> optionalUserParser, Class<T> retArrClass
2222            )
2223        {
2224            return jsonArrToJavaArr(
2225                ja,
2226                RECORD.getFLOATStreamRec(defaultValue, FLAGS, optionalUserParser, true),
2227                CHECK_ARRAY_CLASS(retArrClass, Float.class)
2228            );
2229        }
2230
2231        /**
2232         * Convenience Method.
2233         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2234         * <BR />Passes: {@code Boolean} Configuration-RECORD
2235         * <BR />See link above for more {@link JFlag} explanations.
2236         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Boolean}-array.
2237         * <BR />(See last <B>"return-type"</B> parameter in example below)
2238         * 
2239         * <DIV CLASS=LOC>{@code
2240         * Boolean[][] arr = ReadArrJSON.DimN.arrBOOLEAN
2241         *      (jsonArray, false, 0, null, Boolean[][].class);
2242         * }</DIV>
2243         */
2244        public static <T> T arrBOOLEAN(
2245                JsonArray ja, boolean defaultValue, int FLAGS,
2246                Function<String, Boolean> optionalUserParser, Class<T> retArrClass
2247            )
2248        {
2249            return jsonArrToJavaArr(
2250                ja,
2251                RECORD.getBOOLEANStreamRec(defaultValue, FLAGS, optionalUserParser, true),
2252                CHECK_ARRAY_CLASS(retArrClass, Boolean.class)
2253            );
2254        }
2255
2256        /**
2257         * Convenience Method.
2258         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2259         * <BR />Passes: {@code Number} Configuration-RECORD
2260         * <BR />See link above for more {@link JFlag} explanations.
2261         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Number}-array.
2262         * <BR />(See last <B>"return-type"</B> parameter in example below)
2263         * 
2264         * <DIV CLASS=LOC>{@code
2265         * Number[][] arr = ReadArrJSON.DimN.arrNumber(jsonArray, -1, 0, null, Number[][].class);
2266         * }</DIV>
2267         */
2268        public static <T> T arrNumber(
2269                JsonArray ja, Number defaultValue, int FLAGS,
2270                Function<String, Number> optionalUserParser, Class<T> retArrClass
2271            )
2272        {
2273            return jsonArrToJavaArr(
2274                ja,
2275                RECORD.getNumberStreamRec(defaultValue, FLAGS, optionalUserParser),
2276                CHECK_ARRAY_CLASS(retArrClass, Number.class)
2277            );
2278        }
2279
2280
2281        // ****************************************************************************************
2282        // ****************************************************************************************
2283        // Non-Primitive Multi-Dimensional Array Methods
2284        // ****************************************************************************************
2285        // ****************************************************************************************
2286
2287
2288        /**
2289         * Convenience Method.
2290         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2291         * <BR />Passes: {@code String} Configuration-RECORD
2292         * <BR />See link above for more {@link JFlag} explanations.
2293         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code String}-array.
2294         * <BR />(See last <B>"return-type"</B> parameter in example below)
2295         * 
2296         * <DIV CLASS=LOC>{@code
2297         * String[][] arr = ReadArrJSON.DimN.strArr(jsonArray, null, 0, String[][].class);
2298         * }</DIV>
2299         */
2300        public static <T> T strArr
2301            (JsonArray ja, String defaultValue, int FLAGS, Class<T> retArrClass)
2302        {
2303            return jsonArrToJavaArr(
2304                ja, 
2305                RECORD.getStringStreamRec(defaultValue, FLAGS),
2306                CHECK_ARRAY_CLASS(retArrClass, String.class)
2307            );
2308        }
2309
2310        /**
2311         * Convenience Method.
2312         * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)}
2313         * <BR />Passes: {@code Object} Configuration-RECORD
2314         * <BR />See link above for more {@link JFlag} explanations.
2315         * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Object}-array.
2316         * <BR />(See last <B>"return-type"</B> parameter in example below)
2317         * 
2318         * <DIV CLASS=LOC>{@code
2319         * MyClass[][] arr = ReadArrJSON.DimN.strArr(jsonArray, null, 0, MyClass[][].class);
2320         * }</DIV>
2321         */
2322        @SuppressWarnings({"rawtypes", "unchecked"})
2323        public static <T, U> T objArr
2324            (JsonArray ja, Object defaultValue, int FLAGS, Class<T> retArrClass)
2325        {
2326            Class baseClass = // (Class<U>)
2327                GET_ARRAY_BASE_COMPONENT_CLASS_AND_CHECK(retArrClass, defaultValue);
2328
2329            return jsonArrToJavaArr
2330                (ja, RECORD.getObjectStreamRec(baseClass.cast(defaultValue), FLAGS, baseClass), retArrClass);
2331        }
2332
2333
2334        // ****************************************************************************************
2335        // ****************************************************************************************
2336        // The General Purpose Transformer Method
2337        // ****************************************************************************************
2338        // ****************************************************************************************
2339
2340
2341        /**
2342         * The array processor for this class.  Handles all multi-dimensional array processing
2343         * requests.
2344         * 
2345         * @param <T> The array type being returned.  This {@code java.lang.Class} must be an
2346         * array-class.
2347         * 
2348         * @param ja Any {@link JsonArray}
2349         * @param rec The Configuration-Record
2350         * @param retArrClass The class of the return array type.
2351         * 
2352         * @return An array of type {@code T}
2353         * 
2354         * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html'
2355         *      DATA-FILE-ID=RARR_BS_JNPAEX>
2356         * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JAAEX>
2357         * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JSPAEX>
2358         * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JTAEX>
2359         */
2360        @SuppressWarnings("unchecked")
2361        protected static <T> T jsonArrToJavaArr
2362            (JsonArray ja, RECORD<?, ?> rec, Class<T> retArrClass)
2363        {
2364            // If this is requesting a one-dimensional array, get it using the 1D-Generator,
2365            // and simply return that array.  This requires a cast because there is no way to prove
2366            // to the Java-Compiler that <T> is equal to any return-value at all.
2367            //
2368            // Remember that this is only guaranteed (it works!) because the helper methods are all
2369            // protected or private, and it has been guaranteed through rigorous testing, and
2370            // preventing the user from playing with it!
2371
2372            if (StringParse.countCharacters(retArrClass.getSimpleName(), '[') == 1)
2373                return (T) rec.array1DGenerator.apply(ja);
2374
2375            // Otherwise, this is not a single-dimension (1D) array.  Instead, the JsonArray needs
2376            // to be iterated, and this method called, recursively, on each of the sub-arrays.
2377            //
2378            // NOTE: 'compClass' will also be an array, but with one fewer dimensions
2379
2380            Class<?>    compClass   = retArrClass.getComponentType();
2381            int         SIZE        = ja.size();
2382            T           retArr      = (T) Array.newInstance(compClass, SIZE);
2383            JsonValue   jv          = null;
2384
2385            for (int i=0; i < SIZE; i++)
2386
2387                switch ((jv = ja.get(i)).getValueType())
2388                {
2389                    // javax.json.JsonValue.ValueType.NULL
2390                    case NULL: Array.set(retArr, i, null); break;
2391
2392                    // javax.json.JsonValue.ValueType.ARRAY (JsonArray)
2393                    case ARRAY:
2394                        Array.set
2395                            (retArr, i, jsonArrToJavaArr((JsonArray) jv, rec, compClass));
2396                        break;
2397
2398                    // javax.json.JsonValue.ValueType.TRUE, FALSE, NUMBER, STRING, OBJECT
2399                    default:
2400                        if (rec.IN_NSAT)        Array.set(retArr, i, null);
2401                        else if (rec.S_NSAT)    continue;
2402                        else throw new JsonTypeArrException(ja, i, ARRAY, jv, retArrClass);
2403                }
2404
2405            return retArr;
2406        }
2407    }
2408}