001package Torello.JSON; 002 003import java.util.function.Predicate; 004import java.util.function.Function; 005import java.util.function.ObjIntConsumer; 006import java.util.function.IntConsumer; 007 008import javax.json.JsonString; 009import javax.json.JsonValue; 010 011import static javax.json.JsonValue.ValueType.NUMBER; 012import static javax.json.JsonValue.ValueType.STRING; 013 014import static Torello.JSON.JFlag.*; 015 016// An (extremely) temporary class. This is created in the SettingsRec Constructor, and then it is 017// GC'ed as soon as that Constructor finishes. 018// 019// IMPORTANT NOTE: These booleans are used to decide WHICH Lambda to return. These boolean's 020// ARE NEVER used inside of a Lambda - which (if you try really had to think about 021// it) means the GC will not retain or keep these once the SettingsRec Constructor 022// has finished. 023// 024// 025// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 026// The 'ja' instance declared in class "SettingsRec" **IS NOT** declared final. It can be reset ! 027// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 028// 029// IMPORTANT NOTE: The 'ja' that is passed to the Functional-Interface Implementatons which are 030// constructed in this method is "de-referenced" from the SettingsRec -- It **IS NOT** passed as 031// a parameter to this method. If it **WERE NOT** retrieved from the 'SettingsRec', then 'sr' 032// instance, then the 'ja' that would be used would be permanently-solidified to the 'ja' 033// referenced that were passed right at the beginning, upon construction of the SettingsRec 034// instance. 035 036public class FlagsToHandler<T> 037{ 038 // Internally used flags. These are actually only used during the construction phase, and 039 // therefore these don't have to be "instance fields" at all, they could easily just be final 040 // variables that are used (and then discarded) inside of the constructor only. However, since 041 // there has been a recent "Breaking up the Monolithic Constructor" into smaller pieces, these 042 // were moved here. 043 // 044 // These could also, EASILY, be final-variables that are passed as parameters into the methods 045 // that use them, but this seems OK. The garbage collector really won't know the difference, 046 // because these are primitives. 047 048 private final boolean NULLS, RN_AA, RD_AA, S_AA; 049 050 // Some of the FLAGS. 051 private final boolean RTS_WT, RJA_AEX, IN_NSAT, S_NSAT; 052 053 // A Quick Getter for three of the above private fields 054 boolean RJA_AEX() { return this.RJA_AEX; } 055 boolean IN_NSAT() { return this.IN_NSAT; } 056 boolean S_NSAT() { return this.S_NSAT; } 057 058 // Save the actual-complete FLAGS Mask 059 private final int FLAGS; 060 061 private final ACCEPTOR<T> acceptor; 062 063 FlagsToHandler( 064 final int FLAGS, 065 final boolean NULLS, 066 final ACCEPTOR<T> acceptor 067 ) 068 { 069 this.RJA_AEX = (FLAGS & RETURN_JAPPROX_ON_AEX) > 0; 070 this.RTS_WT = (FLAGS & RETURN_TOSTRING_ON_WRONGTYPE) > 0; 071 this.IN_NSAT = (FLAGS & INSERT_NULL_ON_NON_SUBARRAY_TYPE) > 0; 072 this.S_NSAT = (FLAGS & SKIP_ON_NON_SUBARRAY_TYPE) > 0; 073 074 075 // Fields which are (only) used in the "Handler Selector Methods" below 076 // These could be converted into Final-Variables that are passed as parameters into the 077 // Selector-Methods below, but I chose not too. I don't have a good reason. The way it is 078 // being done, now, is a tiny bit wasteful since they are now saved as Final / Constant 079 // Fields in this class, but they are private and aren't ever used after this constructor 080 // finishes! 081 // 082 // Passing them as a long list of parameters to each of the selector methods would also be 083 // a "Tiny Bit" slower! 084 085 this.NULLS = NULLS; 086 this.RN_AA = NULLS && ((FLAGS & RETURN_NULL_ON_ANY_ALL) > 0); 087 this.RD_AA = (FLAGS & RETURN_DEFVAL_ON_ANY_ALL) > 0; 088 this.S_AA = (FLAGS & SKIP_ON_ANY_ALL) > 0; 089 090 this.FLAGS = FLAGS; 091 this.acceptor = acceptor; 092 } 093 094 095 // Used when Json-Null is encountered in a Json-Array 096 IntConsumer selectNullHandler(final SettingsRec<?, ?> sr) 097 { 098 if (NULLS && ((FLAGS & RETURN_NULL_ON_NULL) > 0)) return acceptor::AN; 099 else if ((FLAGS & RETURN_DEFVAL_ON_NULL) > 0) return this.acceptor::AD; 100 else if ((FLAGS & SKIP_ON_NULL) > 0) return this.acceptor::NOOP; 101 else if (NULLS && RN_AA) return this.acceptor::AN; 102 else if (RD_AA) return this.acceptor::AD; 103 else if (S_AA) return this.acceptor::NOOP; 104 else if (NULLS) return this.acceptor::AN; 105 106 107 // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja' 108 // versus 'ja' (being passed as a parameter to this method). 109 110 else return (int i) -> 111 { throw new JsonNullPrimitiveArrException(sr.ja, i, NUMBER, sr.CLASS); }; 112 } 113 114 // AEX Handler (ArithmeticException) 115 IntConsumer selectAEXHandler() 116 { 117 if (NULLS && ((FLAGS & RETURN_NULL_ON_AEX) > 0)) return this.acceptor::AN; 118 else if ((FLAGS & RETURN_DEFVAL_ON_AEX) > 0) return this.acceptor::AD; 119 else if ((FLAGS & SKIP_ON_AEX) > 0) return this.acceptor::NOOP; 120 else if (NULLS && RN_AA) return this.acceptor::AN; 121 else if (RD_AA) return this.acceptor::AD; 122 else if (S_AA) return this.acceptor::NOOP; 123 124 return null; 125 } 126 127 // SPEX Handler (Exception while parsing a String into the Java-Type) 128 private IntConsumer selectSPEXHandler() 129 { 130 if (NULLS && ((FLAGS & RETURN_NULL_ON_SPEX) > 0)) return this.acceptor::AN; 131 else if ((FLAGS & RETURN_DEFVAL_ON_SPEX) > 0) return this.acceptor::AD; 132 else if ((FLAGS & SKIP_ON_SPEX) > 0) return this.acceptor::NOOP; 133 else if (NULLS && RN_AA) return this.acceptor::AN; 134 else if (RD_AA) return this.acceptor::AD; 135 else if (S_AA) return this.acceptor::NOOP; 136 137 return null; 138 } 139 140 // ZLS Handler (A Zero-Length String was in the JsonArray) 141 private IntConsumer selectZLSHandler() 142 { 143 if (NULLS && ((FLAGS & RETURN_NULL_ON_0LEN_STR) > 0)) return this.acceptor::AN; 144 else if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) > 0) return this.acceptor::AD; 145 else if ((FLAGS & SKIP_ON_0LEN_STR) > 0) return this.acceptor::NOOP; 146 else if (NULLS && RN_AA) return this.acceptor::AN; 147 else if (RD_AA) return this.acceptor::AD; 148 else if (S_AA) return this.acceptor::NOOP; 149 150 return null; 151 } 152 153 // Wrong-Type Handler (A JsonObject or a nested-JsonArray was in an array position) 154 IntConsumer selectWrongTypeHandler() 155 { 156 if (NULLS && ((FLAGS & RN_WT) > 0)) return this.acceptor::AN; 157 else if ((FLAGS & RD_WT) > 0) return this.acceptor::AD; 158 else if ((FLAGS & SKIP_ON_WRONG_JSONTYPE) > 0) return this.acceptor::NOOP; 159 else if (NULLS && RN_AA) return this.acceptor::AN; 160 else if (RD_AA) return this.acceptor::AD; 161 else if (S_AA) return this.acceptor::NOOP; 162 163 return null; 164 } 165 166 167 // JsonString Handler: **ONLY USED BY** ProcessJsonArray.numericToJava 168 <T> ObjIntConsumer<JsonString> selectJsonStringHandler( 169 final SettingsRec<T, ?> sr, 170 final Function<String, T> userParser, 171 172 // BASIC_TYPES: bt.whichType, 173 final byte whichType, 174 175 // BASIC_TYPES: bt.validStrTester, 176 final Predicate<String> validStrTester, 177 178 // BASIC_TYPES: bt.defaultParser 179 final Function<String, T> defaultParser 180 ) 181 { 182 final IntConsumer handlerSPEX = this.selectSPEXHandler(); 183 final IntConsumer handlerZLS = this.selectZLSHandler(); 184 185 if (userParser != null) 186 return ChooseStringHandler.useUserParser 187 (sr, sr.CLASS, sr.acceptor, userParser, handlerSPEX); 188 189 else if ((FLAGS & RP_S) > 0) return (whichType == BASIC_TYPES.NUMBER) 190 191 ? ChooseStringHandler.parseStringNUMBER 192 (sr, sr.CLASS, sr.acceptor, handlerSPEX, handlerZLS) 193 194 : ChooseStringHandler.parseString( 195 sr, sr.CLASS, sr.acceptor, 196 handlerSPEX, handlerZLS, validStrTester, defaultParser 197 ); 198 199 else if (NULLS && ((FLAGS & RETURN_NULL_ON_STR) > 0)) return this.acceptor::AN; 200 else if ((FLAGS & RETURN_DEFVAL_ON_STR) > 0) return this.acceptor::AD; 201 else if ((FLAGS & SKIP_ON_STR) > 0) return this.acceptor::NOOP; 202 else if (NULLS && RN_AA) return this.acceptor::AN; 203 else if (RD_AA) return this.acceptor::AD; 204 else if (S_AA) return this.acceptor::NOOP; 205 206 // Thanksgiving 2024 207 else if (sr.handlerWrongType != null) 208 return (JsonString js, int i) -> sr.handlerWrongType.accept(i); 209 210 211 // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja' 212 // versus 'ja' (being passed as a parameter to this method). 213 214 else return (JsonString js, int i) -> 215 { throw new JsonTypeArrException (sr.ja, i, NUMBER, js, sr.CLASS); }; 216 } 217 218 <T> ObjIntConsumer<JsonValue> selectJsonStringWrongTypeHandler 219 (final SettingsRec<String, ?> sr) 220 { 221 if (this.RTS_WT) 222 return (JsonValue jv, int i) -> sr.acceptor.accept(jv.toString(), i); 223 224 else if (sr.handlerWrongType != null) 225 return (JsonValue jv, int i) -> sr.handlerWrongType.accept(i); 226 227 228 // IMPORTANT NOTE: See the comment at the top of this class regarding the 'sr.ja' 229 // versus 'ja' (being passed as a parameter to this method). 230 231 else return (JsonValue jv, int i) -> 232 { throw new JsonTypeArrException(sr.ja, i, STRING, jv, String.class); }; 233 } 234}