1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package Torello.Java.JSON;

import java.util.function.Supplier;
import java.util.function.Consumer;

import Torello.Java.Additional.EffectivelyFinal;

import java.util.stream.Stream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.DoubleStream;

 
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// SettingsRec is configured to produce a Stream, or an Array
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 
// The purpose of this class is to generate the three Function-Poiters that are needed to process 
// the output of a Json-Array.  The general purpose class "ProcessJsonArray" handles all of the 
// different variants of that are offered for processing a Json-Array.  In order to do this, 
// Java's "Function-Pointers" (which are called "Functional-Interfaces" in Java-Speak) are utilized
// quite extensively in this package.
// 
// This class looks really cryptic, and hard to read.  HOWEVER - IT IS LITERALLY DOING ALMOST
// NOTHING !!
// 
// All that is accomplished is the "wrapping" of the Standard Java Stream-Methods:
//  * Stream.builder()
//  * Stream.Builder.accept()
//  * Stream.Builder.build()
// 
// Into "Lambda's" that are saved as the three fields of this class.  NO MORE NO LESS !
// 
// Oh, and lastly, because the JDK does, indeed, provide three "Primitive Streams"
// -> IntStream, LongStream, DoubleStream
// 
// This class also provides three "alternate static builders" which generate lambda-wrappers for
//  * IntStream.builder()
//  * IntStrea.Builder.accept()
//  * IntStream.Builder.build()
// 
// And that goes double for "LongStream", and triple for "DoubleStream"
// 
// That's all this class does.  These "Wrappers" allow the MAIN PROCESSING LOOP - ProcessJsonArray
// to treat a User-Request for output sent to a "Stream", "Consumer" or "Array" in the exact same
// way, and using the exact same code.
// 
// 
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// Details regarding Java's "Function Pointers" or "Method Pointers"
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 
// This class is used to produce three "Lambdas" or "Functional-Interfaces".  Merely because this 
// Json-Package creates quite a few "Method Pointers" or "Function Poiters" (which is all that a
// Functional-Interface even is) - the contents of the Helper-Classes in this package all look all
// a little bit cryptic.  These are cryptic simply because the "Lambda-Syntax" is pretty well 
// designed, but does, indeed, hide or cover up who-what-when-where these methods are actually ever
// invoked. 
// 
// In a nutshell, there is simply no way to see who or what actually is calling the "acceptor", 
// or the "constructNewBuilder" or "runBuilderDotBuild".  However, because the puporse of these 
// Array-Processing Loops is to be able to handle all variations on User-Requested Handlers by 
// using the exact same code - it is imperative to use Java's Function-Pointers, and it is not
// feasible to get away from them (although it would make the code a lot more readable to do so).
// 
// However, quite literally, the only purpose of this little helper class is to produce or generate
// the three Lambda's - which are all saved as fields in this class.
// 
//  
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// Re-Using a SettingsRec instance with "ProcessJsonArray":
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 
// This is the "Second Major Reason" for this Helper-Class...
// 
// The value of exposing the "SettingsRec" Object to the API is that it allows the user to get an
// instance of this class, in a way that does not require the User to buid a new Settings
// Configuration Record each and every time that a Json-Array needs to be processed.  Creating an
// istance of the "SettingsRec" class, while not very expensive, still requires some amount of 
// extraneously Object-Creating of Objects which are quite short-lived, and become "extra work"
// for the Garbage-Collector / Memory-Manager.
// 
// Creating an instance of "SettingsRec" that is conforms to all of the User's Flags & Default
// Values once, and then using that same record - over and over again - is, indeed, more 
// efficient programming.  THE ONLY CATCH IS THAT - IN THE CASE OF STREAMS - a new 
// Stream.Builder (or IntStream.Builder) instance needs to be constructed each and every time 
// that "ProcessJsonArray".  
// 
// By Saving a "Wrapper" around the methods around 1) Stream.builder(), 2) Stream.Builder.accept()
// and 3) Stream.Builder.build() - reusing the SettingsRec is now a breeze!
// 
// 
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// The classes which invoke this helper include:
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 
//  * RJArrIntoStream,      -> invokes method 'normalStream()' **ONLY**
//  * RJArrIntoBoxedStream  -> invokes method 'normalStream()' **ONLY**
//  * RJArrIntoPrimStream   -> invokes 'intStream()', 'longStream()', 'doubleStream()'
//  * RJArrDimN             -> invokes all of these

class STREAM_BUILDER<DATA_TYPE, STREAM_TYPE>
{
    // ********************************************************************************************
    // ********************************************************************************************
    // Fields
    // ********************************************************************************************
    // ********************************************************************************************


    final Consumer<DATA_TYPE>   acceptor;               // Stream.Builder.accept
    final Runnable              constructNewBuilder;    // Stream.builder()
    final Supplier<STREAM_TYPE> runBuilderDotBuild;     // Stream.Builder.build()


    // ********************************************************************************************
    // ********************************************************************************************
    // Class Lone Constructor, Declared **PRIVATE**
    // ********************************************************************************************
    // ********************************************************************************************


    // This **PRIVATE** Constructor is only used by the four Package-Privte Static-Builder Methods 
    // which are provided below.

    private STREAM_BUILDER(
            final Consumer<DATA_TYPE>   acceptor,
            final Runnable              constructNewBuilder,
            final Supplier<STREAM_TYPE> runBuilderDotBuild
        )
    {
        this.acceptor               = acceptor;
        this.constructNewBuilder    = constructNewBuilder;
        this.runBuilderDotBuild     = runBuilderDotBuild;
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Static-Builder Methods, these invoke this class lone constructor (included directly above)
    // ********************************************************************************************
    // ********************************************************************************************


    static <X> STREAM_BUILDER<X, Stream<X>> normalStream()
    {
        final EffectivelyFinal<Stream.Builder<X>> EF = new EffectivelyFinal<>(null);

        return new STREAM_BUILDER<>(
            (X x)   -> EF.f.accept(x),          // final Consumer<DATA_TYPE> acceptor; 
            ()      -> EF.f = Stream.builder(), // final Runnable constructNewBuilder;
            ()      -> EF.f.build()             // final Supplier<STREAM_TYPE> runBuilderDotBuild;
        );
    }

    // Generates "Method Pointers" which are consistent with Java's "IntStream" Class
    static STREAM_BUILDER<Integer, IntStream> intStream()
    {
        final EffectivelyFinal<IntStream.Builder> EF = new EffectivelyFinal<>(null);

        return new STREAM_BUILDER<>(
            (Integer i) -> EF.f.accept(i.intValue()),   // final Consumer<DATA_TYPE> acceptor; 
            ()          -> EF.f = IntStream.builder(),  // final Runnable constructNewBuilder;
            ()          -> EF.f.build()                 // final Supplier<STREAM_TYPE>
        );                                              //              runBuilderDotBuild;
    }

    // Generates "Method Pointers" which are consistent with Java's "LongStream" Class
    static STREAM_BUILDER<Long, LongStream> longStream()
    {
        final EffectivelyFinal<LongStream.Builder> EF = new EffectivelyFinal<>(null);

        return new STREAM_BUILDER<>(
            (Long l)    -> EF.f.accept(l.longValue()),  // final Consumer<DATA_TYPE> acceptor; 
            ()          -> EF.f = LongStream.builder(), // final Runnable constructNewBuilder;
            ()          -> EF.f.build()                 // final Supplier<STREAM_TYPE>
        );                                              //              runBuilderDotBuild;
    }

    // Generates "Method Pointers" which are consistent with Java's "DoubleStream" Class
    static STREAM_BUILDER<Double, DoubleStream> doubleStream()
    {
        final EffectivelyFinal<DoubleStream.Builder> EF = new EffectivelyFinal<>(null);

        return new STREAM_BUILDER<>(
            (Double d)  -> EF.f.accept(d.doubleValue()),    // final Consumer<DATA_TYPE> acceptor;
            ()          -> EF.f = DoubleStream.builder(),   // final Runnable constructNewBuilder;
            ()          -> EF.f.build()                     // final Supplier<STREAM_TYPE>
        );                                                  //              runBuilderDotBuild;
    }
}