001package Torello.Java.JSON; 002 003import Torello.Java.StringParse; 004import Torello.Java.UnreachableError; 005 006import Torello.Java.Function.FloatConsumer; 007import Torello.Java.Function.IntIntTConsumer; 008import Torello.Java.Function.IntTFunction; 009 010import Torello.Java.Additional.EffectivelyFinal; 011import Torello.Java.Additional.Counter; 012 013import java.math.BigDecimal; 014 015import java.util.function.Consumer; 016import java.util.function.Supplier; 017import java.util.function.Function; 018import java.util.function.Predicate; 019import java.util.function.IntConsumer; 020import java.util.function.ObjIntConsumer; 021import java.util.function.DoubleConsumer; 022 023import javax.json.JsonArray; 024import javax.json.JsonNumber; 025import javax.json.JsonString; 026import javax.json.JsonValue; 027import javax.json.JsonObject; 028 029import static javax.json.JsonValue.ValueType.*; 030import static Torello.Java.JSON.JFlag.*; 031 032/** <EMBED CLASS=external-html DATA-FILE-ID=SETTINGS_REC> */ 033public class SettingsRec<T, U> 034{ 035 // ******************************************************************************************** 036 // ******************************************************************************************** 037 // Instance-Fields: PACKAGE-PRIVATE - These are used OUTSIDE of this class 038 // ******************************************************************************************** 039 // ******************************************************************************************** 040 041 042 // Provided by User-Input, Assigned after construction, cannot be final 043 // When this SettingsRec is used in conjunction withe Multi-Dimensional Array-Processor 044 // this field will be assigned and re-assigned multiple times. 045 // 046 // This field is THE ONLY NON-FINAL FIELD in this class! 047 048 JsonArray ja; 049 050 051 // The Main For-Loop Switch-Statement Handlers! 052 // These are all used in the classes: ProcessJsonArray and JSON_ARRAY_DIMN! 053 054 final IntConsumer handlerWrongType; 055 final IntConsumer handlerNull; 056 final ObjIntConsumer<JsonString> handlerJsonString; 057 final ObjIntConsumer<JsonNumber> handlerNumber; // Added Thanksgiving 2024 058 final ObjIntConsumer<JsonValue> jsonStringWrongTypeHandler; 059 060 061 // Allows the user to provide *ANY* lambda function, not just the constructor of an object 062 // when attempting to handle Json-Array's which contain Objects. This field will be null in 063 // cases of building this Settings-Record instance - **UNLESS** this instance of SettingsRec is 064 // being constructed for processing an array of JsonObject's. 065 // 066 // ALSO, as of May 2025: There are officially two variants of the exact same "Static-Builder" 067 // Lambda's / Functional-Interfaces. BOTH of these fields are only used inside the classes 068 // RJArrIntoStream & RJArrIntoConsumer - and only in the 'objArr' and 'objRec' Methods!! 069 // 070 // The second 'objBuilder2' was added to allow for writing Static-Builder Methods which also 071 // accept the Json-Array-Index, and the Java-Processed-Output-Index (or whatever you want to 072 // call the little 'Torello.Java.Additional.Counter' that is inserted inside the builder) 073 074 final Function<JsonObject, T> objBuilder; 075 final IntTFunction<JsonObject, T> objBuilder2; 076 final boolean builder1Or2; 077 078 079 // Copied directly from Helper-Class BASIC_TYPES, at the very beginning of this class 080 // Constructor-Body 081 082 final Class<T> CLASS; 083 084 085 // This is the top-level "handler" for results that are to be sent to the user 086 // This will either be a consumer that the user himself provided, or it will be a 087 // Stream-Acceptor method that was produced in a sub-class constructor, and passed here 088 // 089 // final Consumer<T> acceptor; 090 // final ObjIntConsumer<T> acceptor2; 091 // final boolean version1OrVersion2; 092 093 final ObjIntConsumer<T> ACCEPTOR; 094 095 096 // These are only used for Stream's, **NOT** Consumer's 097 // Invokes: Stream.builder(), IntStream.builder(), DoubleStream.builder(), etc... 098 099 final Runnable constructNewBuilder; 100 101 102 // These are only used for Stream's, **NOT** Consumer's 103 // Invokes: Stream.Builder.build(), IntStream.Builder.build(), etc... 104 105 final Supplier<U> runBuilderDotBuild; 106 107 // This is only used for Multi-Dimensional Array-Processing 108 final Function<JsonArray, Object> array1DGenerator; 109 final boolean IN_NSAT, S_NSAT; 110 111 112 // ******************************************************************************************** 113 // ******************************************************************************************** 114 // Package-Private SettingsRec Constructor 115 // ******************************************************************************************** 116 // ******************************************************************************************** 117 118 119 // The very last line of this method has a cast of SettingsRec<> 120 @SuppressWarnings("unchecked") 121 SettingsRec( 122 123 // Parameters passed by the user to initial query 124 final T defaultValue, 125 final int FLAGS, 126 final Function<String, T> userParser, 127 128 // Configuration Stuff (Copied Directly from class "BASIC_TYPES") 129 final BASIC_TYPES<T> bt, 130 131 // Sir, Where would you prefer I shove this data? 132 final Consumer<T> acceptor, 133 final Runnable constructNewBuilder, 134 final Supplier<U> runBuilderDotBuild, 135 136 // acceptor2: The "IntIntTConsumer" variant of an acceptor 137 final IntIntTConsumer<T> acceptor2, 138 139 140 // Informs this constructor how to build a 1-Dimensional Array for the 141 // Multi-Dimensional Array-Processor 142 143 final Boolean arrayGen1DRefOrPrimitive 144 ) 145 { 146 // Configurations determined by type, from class BASIC_TYES 147 this.CLASS = bt.CLASS; 148 149 // Where to send the data. Consumer? Stream-Builder? (and eventually a Stream or Array) 150 // this.acceptor = acceptor; 151 this.constructNewBuilder = constructNewBuilder; 152 this.runBuilderDotBuild = runBuilderDotBuild; 153 154 155 // This cute little thing is a "Later Addition". It provides the second "suite" of methods 156 // in the RJ Into-Consumer Series. The user now has the option to provide a consumer that 157 // accepts the Array-Indices as well. 158 // 159 // Also note, that this concept is "identical" to the Stream-Object method (inside class 160 // RJArrIntoStream) which allows for a Static-Builder Lambda that accepts a Json-Object and 161 // the Java Array-Indices. However, in this portion of the code, this concept is used, 162 // *STRICTLY* for the classes: 163 // RJArrIntoConsumer, RJArrIntoBoxedConsumer, RJArrIntoPrimConsumer 164 165 final boolean version1OrVersion2 = (acceptor2 == null); 166 167 if (version1OrVersion2) 168 this.ACCEPTOR = (T theValue, int ignoreThisIndex) -> acceptor.accept(theValue); 169 else 170 { 171 final Counter javaArrayIndex = new Counter(-1); 172 173 this.ACCEPTOR = (T theValue, int jsonArrayIndex) -> 174 acceptor2.accept(jsonArrayIndex, javaArrayIndex.addOne(), theValue); 175 } 176 177 178 // Only used for building Multi-Dimensional Array's (rarely needed) 179 this.array1DGenerator = (arrayGen1DRefOrPrimitive == null) 180 ? null 181 : GENERATE_1DARRAY.retrieveAppropriateGenerator(this, bt, arrayGen1DRefOrPrimitive); 182 183 184 // This is the "new thing". It allows *ANY* lambda (not just a constructor) to produce 185 // an Object of type 'T' This field is *ALWAYS* null - *UNLESS* this instance of 186 // SettingsRec is being configured to handle Json-Array's which contains objects (not one 187 // of the standard primitive, number or string types). 188 // 189 // Note the "Marker Boolean" is computed because these are used inside of a loop. 190 // Also, by default, if the user isn't asking for the Objects to be built, then this 191 // booean to be assigned 'false', because - in such cases - it just wouldn't matter in the 192 // slightest. 193 194 this.objBuilder = bt.objBuilder; 195 this.objBuilder2 = bt.objBuilder2; 196 this.builder1Or2 = (bt.objBuilder != null); 197 198 199 // This is a temporary class that is not used once this constructor has 200 // completed! Hopefully the garbage collector picks it up as soon as this is finished. 201 // The "TempFlags" actually does a lot of the dispatch for deciding what handler's / 202 // Lambda's are to be used when Processing a JsonArray. 203 204 final TempFlags flags = new TempFlags( 205 FLAGS, 206 bt.referenceOrPrimitive, 207 new Lambdas<T>(this.ACCEPTOR, defaultValue) 208 ); 209 210 // Two little flags that are used by the Multi-Dimensional Array Processor 211 this.IN_NSAT = flags.IN_NSAT(); 212 this.S_NSAT = flags.S_NSAT(); 213 214 this.handlerNull = flags.selectNullHandler(this); 215 this.handlerWrongType = flags.selectWrongTypeHandler(); 216 217 218 // "handlerJsonString" is used for both Number-Stuff and Boolean 219 // It is not Used for String or Object... 220 // 221 // If you want to learn where this is used, just go to "ProcessJsonArray", 222 // and you will see all of these cute little dispatch/handler dealy's hard at work 223 224 this.handlerJsonString = 225 (bt.whichType != BASIC_TYPES.STRING) && (bt.whichType != BASIC_TYPES.OBJECT) 226 ? flags.selectJsonStringHandler( 227 this, 228 userParser, 229 bt.whichType, 230 bt.validStrTester, 231 bt.defaultParser 232 ) 233 : null; 234 235 236 // The field "isNumberType" is only true if this is actually used to convert a 237 // a JsonNumber into a Java-Number. This will be false for Strings, Objects & Booleans! 238 239 this.handlerNumber = bt.isNumberType 240 ? ChooseNumberHandler.choose( 241 this, 242 this.ACCEPTOR, 243 bt.whichType, 244 bt.referenceOrPrimitive, 245 bt.numberConverter, 246 bt.numberConverterExThrow, 247 bt.jsonNumWillFit, 248 flags.RJA_AEX(), 249 flags.selectAEXHandler() 250 ) 251 : null; 252 253 254 // TIf you look at "ProcessJsonArray" - this is only used for converting 255 // JsonArray's of String. All other types will never use this handler. Therefore, in 256 // any case where a User HAS NOT requested to process a JsonArray of Strings, leaving this 257 // handler as 'null' will have no effect, and it certainly won't cause NullPointerException 258 259 this.jsonStringWrongTypeHandler = (bt.whichType == BASIC_TYPES.STRING) 260 ? flags.selectJsonStringWrongTypeHandler((SettingsRec<String, ?>) this) 261 : null; 262 } 263 264}