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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | package Torello.Java.JSON; import Torello.Java.StringParse; import Torello.Java.UnreachableError; import Torello.Java.Function.FloatConsumer; import Torello.Java.Function.IntIntTConsumer; import Torello.Java.Function.IntTFunction; import Torello.Java.Additional.EffectivelyFinal; import Torello.Java.Additional.Counter; import java.math.BigDecimal; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.IntConsumer; import java.util.function.ObjIntConsumer; import java.util.function.DoubleConsumer; import javax.json.JsonArray; import javax.json.JsonNumber; import javax.json.JsonString; import javax.json.JsonValue; import javax.json.JsonObject; import static javax.json.JsonValue.ValueType.*; import static Torello.Java.JSON.JFlag.*; /** <EMBED CLASS=external-html DATA-FILE-ID=SETTINGS_REC> */ public class SettingsRec<T, U> { // ******************************************************************************************** // ******************************************************************************************** // Instance-Fields: PACKAGE-PRIVATE - These are used OUTSIDE of this class // ******************************************************************************************** // ******************************************************************************************** // Provided by User-Input, Assigned after construction, cannot be final // When this SettingsRec is used in conjunction withe Multi-Dimensional Array-Processor // this field will be assigned and re-assigned multiple times. // // This field is THE ONLY NON-FINAL FIELD in this class! JsonArray ja; // The Main For-Loop Switch-Statement Handlers! // These are all used in the classes: ProcessJsonArray and JSON_ARRAY_DIMN! final IntConsumer handlerWrongType; final IntConsumer handlerNull; final ObjIntConsumer<JsonString> handlerJsonString; final ObjIntConsumer<JsonNumber> handlerNumber; // Added Thanksgiving 2024 final ObjIntConsumer<JsonValue> jsonStringWrongTypeHandler; // Allows the user to provide *ANY* lambda function, not just the constructor of an object // when attempting to handle Json-Array's which contain Objects. This field will be null in // cases of building this Settings-Record instance - **UNLESS** this instance of SettingsRec is // being constructed for processing an array of JsonObject's. // // ALSO, as of May 2025: There are officially two variants of the exact same "Static-Builder" // Lambda's / Functional-Interfaces. BOTH of these fields are only used inside the classes // RJArrIntoStream & RJArrIntoConsumer - and only in the 'objArr' and 'objRec' Methods!! // // The second 'objBuilder2' was added to allow for writing Static-Builder Methods which also // accept the Json-Array-Index, and the Java-Processed-Output-Index (or whatever you want to // call the little 'Torello.Java.Additional.Counter' that is inserted inside the builder) final Function<JsonObject, T> objBuilder; final IntTFunction<JsonObject, T> objBuilder2; final boolean builder1Or2; // Copied directly from Helper-Class BASIC_TYPES, at the very beginning of this class // Constructor-Body final Class<T> CLASS; // This is the top-level "handler" for results that are to be sent to the user // This will either be a consumer that the user himself provided, or it will be a // Stream-Acceptor method that was produced in a sub-class constructor, and passed here // // final Consumer<T> acceptor; // final ObjIntConsumer<T> acceptor2; // final boolean version1OrVersion2; final ObjIntConsumer<T> ACCEPTOR; // These are only used for Stream's, **NOT** Consumer's // Invokes: Stream.builder(), IntStream.builder(), DoubleStream.builder(), etc... final Runnable constructNewBuilder; // These are only used for Stream's, **NOT** Consumer's // Invokes: Stream.Builder.build(), IntStream.Builder.build(), etc... final Supplier<U> runBuilderDotBuild; // This is only used for Multi-Dimensional Array-Processing final Function<JsonArray, Object> array1DGenerator; final boolean IN_NSAT, S_NSAT; // ******************************************************************************************** // ******************************************************************************************** // Package-Private SettingsRec Constructor // ******************************************************************************************** // ******************************************************************************************** // The very last line of this method has a cast of SettingsRec<> @SuppressWarnings("unchecked") SettingsRec( // Parameters passed by the user to initial query final T defaultValue, final int FLAGS, final Function<String, T> userParser, // Configuration Stuff (Copied Directly from class "BASIC_TYPES") final BASIC_TYPES<T> bt, // Sir, Where would you prefer I shove this data? final Consumer<T> acceptor, final Runnable constructNewBuilder, final Supplier<U> runBuilderDotBuild, // acceptor2: The "IntIntTConsumer" variant of an acceptor final IntIntTConsumer<T> acceptor2, // Informs this constructor how to build a 1-Dimensional Array for the // Multi-Dimensional Array-Processor final Boolean arrayGen1DRefOrPrimitive ) { // Configurations determined by type, from class BASIC_TYES this.CLASS = bt.CLASS; // Where to send the data. Consumer? Stream-Builder? (and eventually a Stream or Array) // this.acceptor = acceptor; this.constructNewBuilder = constructNewBuilder; this.runBuilderDotBuild = runBuilderDotBuild; // This cute little thing is a "Later Addition". It provides the second "suite" of methods // in the RJ Into-Consumer Series. The user now has the option to provide a consumer that // accepts the Array-Indices as well. // // Also note, that this concept is "identical" to the Stream-Object method (inside class // RJArrIntoStream) which allows for a Static-Builder Lambda that accepts a Json-Object and // the Java Array-Indices. However, in this portion of the code, this concept is used, // *STRICTLY* for the classes: // RJArrIntoConsumer, RJArrIntoBoxedConsumer, RJArrIntoPrimConsumer final boolean version1OrVersion2 = (acceptor2 == null); if (version1OrVersion2) this.ACCEPTOR = (T theValue, int ignoreThisIndex) -> acceptor.accept(theValue); else { final Counter javaArrayIndex = new Counter(-1); this.ACCEPTOR = (T theValue, int jsonArrayIndex) -> acceptor2.accept(jsonArrayIndex, javaArrayIndex.addOne(), theValue); } // Only used for building Multi-Dimensional Array's (rarely needed) this.array1DGenerator = (arrayGen1DRefOrPrimitive == null) ? null : GENERATE_1DARRAY.retrieveAppropriateGenerator(this, bt, arrayGen1DRefOrPrimitive); // This is the "new thing". It allows *ANY* lambda (not just a constructor) to produce // an Object of type 'T' This field is *ALWAYS* null - *UNLESS* this instance of // SettingsRec is being configured to handle Json-Array's which contains objects (not one // of the standard primitive, number or string types). // // Note the "Marker Boolean" is computed because these are used inside of a loop. // Also, by default, if the user isn't asking for the Objects to be built, then this // booean to be assigned 'false', because - in such cases - it just wouldn't matter in the // slightest. this.objBuilder = bt.objBuilder; this.objBuilder2 = bt.objBuilder2; this.builder1Or2 = (bt.objBuilder != null); // This is a temporary class that is not used once this constructor has // completed! Hopefully the garbage collector picks it up as soon as this is finished. // The "TempFlags" actually does a lot of the dispatch for deciding what handler's / // Lambda's are to be used when Processing a JsonArray. final TempFlags flags = new TempFlags( FLAGS, bt.referenceOrPrimitive, new Lambdas<T>(this.ACCEPTOR, defaultValue) ); // Two little flags that are used by the Multi-Dimensional Array Processor this.IN_NSAT = flags.IN_NSAT(); this.S_NSAT = flags.S_NSAT(); this.handlerNull = flags.selectNullHandler(this); this.handlerWrongType = flags.selectWrongTypeHandler(); // "handlerJsonString" is used for both Number-Stuff and Boolean // It is not Used for String or Object... // // If you want to learn where this is used, just go to "ProcessJsonArray", // and you will see all of these cute little dispatch/handler dealy's hard at work this.handlerJsonString = (bt.whichType != BASIC_TYPES.STRING) && (bt.whichType != BASIC_TYPES.OBJECT) ? flags.selectJsonStringHandler( this, userParser, bt.whichType, bt.validStrTester, bt.defaultParser ) : null; // The field "isNumberType" is only true if this is actually used to convert a // a JsonNumber into a Java-Number. This will be false for Strings, Objects & Booleans! this.handlerNumber = bt.isNumberType ? ChooseNumberHandler.choose( this, this.ACCEPTOR, bt.whichType, bt.referenceOrPrimitive, bt.numberConverter, bt.numberConverterExThrow, bt.jsonNumWillFit, flags.RJA_AEX(), flags.selectAEXHandler() ) : null; // TIf you look at "ProcessJsonArray" - this is only used for converting // JsonArray's of String. All other types will never use this handler. Therefore, in // any case where a User HAS NOT requested to process a JsonArray of Strings, leaving this // handler as 'null' will have no effect, and it certainly won't cause NullPointerException this.jsonStringWrongTypeHandler = (bt.whichType == BASIC_TYPES.STRING) ? flags.selectJsonStringWrongTypeHandler((SettingsRec<String, ?>) this) : null; } } |