001package Torello.JSON;
002
003import Torello.JavaDoc.Annotations.IntoHTMLTable;
004import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.GreenDither;
005import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.BlueDither;
006
007import javax.json.JsonArray;
008import javax.json.JsonObject;
009import javax.json.JsonValue;
010import javax.json.JsonNumber;
011import javax.json.JsonString;
012
013import static javax.json.JsonValue.ValueType.*;
014
015import java.math.BigDecimal;
016import java.util.function.Function;
017import java.util.function.ObjIntConsumer;
018
019/**
020 * This class is the "Central Artery" for all Json-Array Processing done in this package.
021 * These four FOR-LOOPS handle 100% of the array processors done by all of the "RJArr"
022 * classes offered.
023 *  
024 * These four methods are extremely similar, but have a few minor subtleties that prevent 
025 * them from being unified into a single handler for all types.
026 */
027@Torello.JavaDoc.Annotations.StaticFunctional
028public class ProcessJsonArray
029{
030    private ProcessJsonArray() { }
031
032
033    // ********************************************************************************************
034    // ********************************************************************************************
035    // Un-Synchronized Method Variants
036    // ********************************************************************************************
037    // ********************************************************************************************
038
039
040    /**
041     * Any and all Json-Array Processors that are intended to read an array of {@link JsonNumber}
042     * will invoke this method to do their Type-Conversions.
043     * 
044     * @param <NUMERIC_DATA_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_NUM_DATA_TYPE>
045     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_NUM_RETURN_TYPE>
046     * 
047     * @param ja This should be any instance of {@link JsonArray}.  It is expected that if this
048     * array does not contain explicit {@link JsonNumber} values, that is should at least contain
049     * values that are to converted or properly parsed into Java-Numbers.
050     * 
051     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
052     * 
053     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}
054     */
055    public static <NUMERIC_DATA_TYPE extends Number, RETURN_TYPE> RETURN_TYPE numericToJava(
056            final JsonArray                                     ja,
057            final SettingsRec<NUMERIC_DATA_TYPE, RETURN_TYPE>   rec
058        )
059    {
060        final int SIZE  = ja.size();
061        JsonValue jv    = null;
062        rec.ja          = ja;
063
064        rec.opener.run();
065        rec.acceptor.reset();
066
067        for (int i=0; i < SIZE; i++)
068
069            switch ((jv = ja.get(i)).getValueType())
070            {
071                // javax.json.JsonValue.ValueType.NULL
072                case NULL: rec.handlerNull.accept(i); break;
073
074                // javax.json.JsonValue.ValueType.NUMBER
075                case NUMBER: rec.handlerNumber.accept((JsonNumber) jv, i); break;
076
077                // javax.json.JsonValue.ValueType.STRING
078                case STRING: rec.handlerJsonString.accept((JsonString) jv, i); break;
079
080                // OBJECT, ARRAY, TRUE, FALSE
081                default:
082
083                    if (rec.handlerWrongType != null)
084                        rec.handlerWrongType.accept(i);
085                    else
086                        throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS);
087            }
088
089        return rec.closer.get();
090    }
091
092    /**
093     * Any and all Json-Array Processors that are intended to read an array of Json-Boolean Values
094     * will invoke this method to do their Type-Conversions.
095     * 
096     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_BL_RETURN_TYPE>
097     * 
098     * @param ja This should be any instance of {@link JsonArray}.  It is expected that if this
099     * array does not contain explicit Json-Boolean values, that is should at least contain values
100     * that are to converted or properly parsed into Java-Booleans.
101     * 
102     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
103     * 
104     * @return An instance of {@code Stream<Boolean>}.  If the provided instance of 
105     * {@code SettingsRec} has been constructed for a {@code Consumer}, then this method will  
106     * return null.
107     */
108    public static <RETURN_TYPE> RETURN_TYPE booleanToJava(
109            final JsonArray                         ja,
110            final SettingsRec<Boolean, RETURN_TYPE> rec
111        )
112    {
113        final int SIZE  = ja.size();
114        JsonValue jv    = null;
115        rec.ja          = ja;
116
117        rec.opener.run();
118        rec.acceptor.reset();
119
120        for (int i=0; i < SIZE; i++)
121
122            switch ((jv = ja.get(i)).getValueType())
123            {
124                // javax.json.JsonValue.ValueType.NULL, TRUE, FALSE & STRING
125                case NULL:      rec.handlerNull.accept(i); break;
126                case TRUE:      rec.acceptor.accept(true, i); break;
127                case FALSE:     rec.acceptor.accept(false, i); break;
128                case STRING:    rec.handlerJsonString.accept((JsonString) jv, i); break;
129
130                // javax.json.JsonValue.ValueType.NUMBER, OBJECT, ARRAY
131                default:
132                    if (rec.handlerWrongType != null) rec.handlerWrongType.accept(i);
133                    else throw new JsonTypeArrException(ja, i, TRUE, jv, Boolean.class);
134            }
135
136        return rec.closer.get();
137    }
138
139    /**
140     * Used to convert {@code JsonObject}'s into Java-Objects
141     * 
142     * @param <T> The Class / Type of the Objects to be extracted from the {@link JsonArray}
143     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_T_RETURN_TYPE>
144     * 
145     * @param ja This should be any instance of {@link JsonArray}.  It is expected that this array
146     * contain explicit {@link JsonObject} values, that can be converted in.to {@code 'T'}
147     * 
148     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
149     * 
150     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}.
151     */
152    public static <T, RETURN_TYPE> RETURN_TYPE objToJava(
153            final JsonArray                     ja,
154            final SettingsRec<T, RETURN_TYPE>   rec
155        )
156    {
157        final int SIZE  = ja.size();
158        JsonValue jv    = null;
159        rec.ja          = ja;
160
161        rec.opener.run();
162        rec.acceptor.reset();
163
164        for (int i=0; i < SIZE; i++)
165
166            switch ((jv = ja.get(i)).getValueType())
167            {
168                // javax.json.JsonValue.ValueType.NULL
169                case NULL:
170                    rec.handlerNull.accept(i);
171                    break;
172
173                // javax.json.JsonValue.ValueType.OBJECT
174                case OBJECT:
175                    final JsonObject jo = (JsonObject) jv;
176
177                    try 
178                    {
179                        final T POJO = rec.builder1Or2
180                            ? rec.singleArgUserTypeBuilder.apply(jo)
181                            : rec.tripleArgUserTypeBuilder.apply(i, jo);
182
183                        rec.acceptor.accept(POJO, i);
184                    }
185    
186                    catch (Exception e)
187                        { throw new JsonBuildPOJOArrException(e, ja, i, jo, rec.CLASS); }
188
189                    break;
190
191                // javax.json.JsonValue.ValueType.NUMBER, STRING, TRUE, FALSE, ARRAY
192                default:
193                    if (rec.handlerWrongType != null) rec.handlerWrongType.accept(i);
194                    else throw new JsonTypeArrException(ja, i, TRUE, jv, rec.CLASS);
195            }
196
197        return rec.closer.get();
198    }
199
200    /**
201     * Any and all Json-Array Processors that are intended to read an array of {@link JsonString}
202     * Values will invoke this method to do their Type-Conversions.
203     * 
204     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_STR_RETURN_TYPE>
205     * 
206     * @param ja This should be any instance of {@link JsonArray}.
207     * 
208     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
209     * 
210     * @return An instance of {@code Stream<String>}.  If the provided instance of
211     * {@code SettingsRec} has been constructed for a {@code Consumer}, then this method will
212     * return null.
213     */
214    public static <RETURN_TYPE> RETURN_TYPE strToJava(
215            final JsonArray                         ja,
216            final SettingsRec<String, RETURN_TYPE>  rec
217        )
218    {
219        final int SIZE  = ja.size();
220        JsonValue jv    = null;
221        rec.ja          = ja;
222
223        rec.opener.run();
224        rec.acceptor.reset();
225
226        for (int i=0; i < SIZE; i++)
227
228            switch ((jv = ja.get(i)).getValueType())
229            {
230                // javax.json.JsonValue.ValueType.NULL
231                case NULL:
232                    rec.handlerNull.accept(i);
233                    break;
234
235                // javax.json.JsonValue.ValueType.STRING
236                case STRING:
237                    rec.acceptor.accept(((JsonString) jv).getString(), i);
238                    break;
239
240                // OBJECT, ARRAY, TRUE, FALSE, NUMBER
241                default:
242                    rec.jsonStringWrongTypeHandler.accept(jv, i);
243            }
244
245        return rec.closer.get();
246    }
247
248    /**
249     * Invoke this method in order to read an array of {@link JsonObject JsonObject's}
250     * 
251     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_JO_RETURN_TYPE>
252     * 
253     * @param ja This should be any instance of {@link JsonArray}.  It is expected that the
254     * elements of this {@code JsonArray} are, themselves, {@code JsonObject's}
255     * 
256     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
257     * 
258     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}
259     * (explained above).
260     */
261    public static <RETURN_TYPE> RETURN_TYPE joToJava(
262            final JsonArray                             ja,
263            final SettingsRec<JsonObject, RETURN_TYPE>  rec
264        )
265    {
266        final int SIZE  = ja.size();
267        JsonValue jv    = null;
268        rec.ja          = ja;
269
270        rec.opener.run();
271        rec.acceptor.reset();
272
273        for (int i=0; i < SIZE; i++)
274
275            switch ((jv = ja.get(i)).getValueType())
276            {
277                // javax.json.JsonValue.ValueType.NULL
278                case NULL: rec.handlerNull.accept(i); break;
279
280                // javax.json.JsonValue.ValueType.OBJECT
281                case OBJECT: rec.acceptor.accept((JsonObject) jv, i); break;
282
283                // NUMBER, STRING, ARRAY, TRUE, FALSE
284                default:
285
286                    if (rec.handlerWrongType != null)
287                        rec.handlerWrongType.accept(i);
288                    else
289                        throw new JsonTypeArrException(ja, i, OBJECT, jv, rec.CLASS);
290            }
291
292        return rec.closer.get();
293    }
294
295    /**
296     * Invoke this method in order to read an array of {@link JsonArray JsonArray's}
297     * 
298     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_JA_RETURN_TYPE>
299     * 
300     * @param ja This should be any instance of {@link JsonArray}.  It is expected that the
301     * elements of this {@code JsonArray} are, themselves, {@code JsonArray's}
302     * 
303     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
304     * 
305     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}
306     * (explained above).
307     */
308    public static <RETURN_TYPE> RETURN_TYPE jaToJava(
309            final JsonArray                             ja,
310            final SettingsRec<JsonArray, RETURN_TYPE>   rec
311        )
312    {
313        final int SIZE  = ja.size();
314        JsonValue jv    = null;
315        rec.ja          = ja;
316
317        rec.opener.run();
318        rec.acceptor.reset();
319
320        for (int i=0; i < SIZE; i++)
321
322            switch ((jv = ja.get(i)).getValueType())
323            {
324                // javax.json.JsonValue.ValueType.NULL
325                case NULL: rec.handlerNull.accept(i); break;
326
327                // javax.json.JsonValue.ValueType.OBJECT
328                case ARRAY: rec.acceptor.accept((JsonArray) jv, i); break;
329
330                // NUMBER, STRING, OBJECT, TRUE, FALSE
331                default:
332
333                    if (rec.handlerWrongType != null)
334                        rec.handlerWrongType.accept(i);
335                    else
336                        throw new JsonTypeArrException(ja, i, ARRAY, jv, rec.CLASS);
337            }
338
339        return rec.closer.get();
340    }
341
342
343    // ********************************************************************************************
344    // ********************************************************************************************
345    // Synchronized Method Variants
346    // ********************************************************************************************
347    // ********************************************************************************************
348
349
350    /**
351     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
352     *                   Multi-Threaded Programming-Environment.
353     * <BR>Wraps: Method {@link #numericToJava(JsonArray, SettingsRec)}
354     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
355     * <BR>IMPORTANT: Synchronization <B><I>is only needed</I></B> when the {@code SettingsRec}
356     *                instance shall be "re-used" in other threads.
357     * @see #numericToJava(JsonArray, SettingsRec)
358     */
359    @IntoHTMLTable(background=BlueDither, title="Synchronized Variant of Method 'numericToJava'")
360    public static <NUMERIC_DATA_TYPE extends Number, RETURN_TYPE> RETURN_TYPE
361        numericToJavaSync(
362            final JsonArray                                     ja,
363            final SettingsRec<NUMERIC_DATA_TYPE, RETURN_TYPE>   rec
364        )
365    { synchronized (rec) { return numericToJava(ja, rec); } }
366
367    /**
368     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
369     *                   Multi-Threaded Programming-Environment.
370     * <BR>Wraps: Method {@link #booleanToJava(JsonArray, SettingsRec)}
371     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
372     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
373     *                instance shall be "re-used" in other threads.
374     * @see #booleanToJava(JsonArray, SettingsRec)
375     */
376    @IntoHTMLTable(background=GreenDither, title="Synchronized Variant of Method 'booleanToJava'")
377    public static <RETURN_TYPE> RETURN_TYPE booleanToJavaSync(
378            final JsonArray                         ja,
379            final SettingsRec<Boolean, RETURN_TYPE> rec
380        )
381    { synchronized (rec) { return booleanToJava(ja, rec); } }
382
383    /**
384     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
385     *                     Multi-Threaded Programming-Environment.
386     * <BR>Wraps: Method {@link #objToJava(JsonArray, SettingsRec)}
387     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
388     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
389     *                instance shall be "re-used" in other threads.
390     * @see #objToJava(JsonArray, SettingsRec)
391     */
392    @IntoHTMLTable(background=BlueDither, title="Synchronized Variant of Method 'objToJava'")
393    public static <T, RETURN_TYPE> RETURN_TYPE objToJavaSync(
394            final JsonArray                     ja,
395            final SettingsRec<T, RETURN_TYPE>   rec
396        )
397    { synchronized (rec) { return objToJava(ja, rec); } }
398
399    /**
400     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
401     *                     Multi-Threaded Programming-Environment.
402     * <BR>Wraps: Method {@link #strToJava(JsonArray, SettingsRec)}
403     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
404     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
405     *                instance shall be "re-used" in other threads.
406     * @see #strToJava(JsonArray, SettingsRec)
407     */
408    @IntoHTMLTable(background=GreenDither, title="Synchronized Variant of Method 'strToJava'")
409    public static <RETURN_TYPE> RETURN_TYPE strToJavaSync(
410        final JsonArray                         ja,
411        final SettingsRec<String, RETURN_TYPE>  rec
412    )
413    { synchronized (rec) { return strToJava(ja, rec); } }
414
415    /**
416     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
417     *                     Multi-Threaded Programming-Environment.
418     * <BR>Wraps: Method {@link #joToJava(JsonArray, SettingsRec)}
419     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
420     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
421     *                instance shall be "re-used" in other threads.
422     * @see #joToJava(JsonArray, SettingsRec)
423     */
424    @IntoHTMLTable(background=BlueDither, title="Synchronized Variant of Method 'joToJava'")
425    public static <RETURN_TYPE> RETURN_TYPE joToJavaSync(
426        final JsonArray                             ja,
427        final SettingsRec<JsonObject, RETURN_TYPE>   rec
428    )
429    { synchronized (rec) { return joToJava(ja, rec); } }
430
431    /**
432     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
433     *                     Multi-Threaded Programming-Environment.
434     * <BR>Wraps: Method {@link #jaToJava(JsonArray, SettingsRec)}
435     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
436     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
437     *                instance shall be "re-used" in other threads.
438     * @see #jaToJava(JsonArray, SettingsRec)
439     */
440    @IntoHTMLTable(background=GreenDither, title="Synchronized Variant of Method 'jaToJava'")
441    public static <RETURN_TYPE> RETURN_TYPE jaToJavaSync(
442        final JsonArray                             ja,
443        final SettingsRec<JsonArray, RETURN_TYPE>   rec
444    )
445    { synchronized (rec) { return jaToJava(ja, rec); } }
446
447
448}