001package Torello.Java.JSON; 002 003import Torello.Java.StringParse; 004import Torello.Java.UnreachableError; 005 006import Torello.Java.Additional.Ret3; 007import Torello.Java.Additional.EffectivelyFinal; 008import Torello.Java.Additional.Counter; 009 010import Torello.Java.Function.ToByteFunction; 011import Torello.Java.Function.ToFloatFunction; 012import Torello.Java.Function.ToShortFunction; 013 014import java.util.*; 015import java.util.stream.*; 016import java.util.function.*; 017import java.math.*; 018import javax.json.*; 019 020import java.lang.reflect.Array; 021 022// This is "The Great Sillyness" - it is only used because of the Java-Quirk about constructor's 023// not referencing "this" before a call to "super(...)" or "this(...)". The only way around it I 024// have ever found is to use a static-temporary variable, and set its value inside of a static 025// helper-method. 026// 027// This is, essentially, just fine. However, if the user ever ran this in a multi-threaded program 028// it might "get messed up". TO PREVENT THAT: You have to have a few lines that are synchronized. 029// Using the "ReentrantLock" is easier for me to think about than using "synchronized" 030// 031// NOTE: There is NO MULTI-THREADED CALLS IN THIS CLASS WHATSOEVER. This is only used as a 032// "Constructor-Helper" 033// 034// THIS CLASS IS **VERY** THREAD-SAFE 035 036import java.util.concurrent.locks.ReentrantLock; 037 038import static javax.json.JsonValue.ValueType.*; 039import static Torello.Java.JSON.JFlag.*; 040 041/** 042 * Utilities for parsing Json Array's into Java Array's. 043 * 044 * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE> 045 * <EMBED CLASS='external-html' DATA-FILE-ID=READ_ARR_JSON> 046 * 047 * @see Json 048 * @see Json 049 * @see JsonArray 050 */ 051@Torello.JavaDoc.StaticFunctional 052@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI") 053public class ReadArrJSON 054{ 055 private ReadArrJSON() { } 056 057 // ******************************************************************************************** 058 // ******************************************************************************************** 059 // TEST-PREDICATE'S 060 // ******************************************************************************************** 061 // ******************************************************************************************** 062 063 064 private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE); 065 private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE); 066 private static final BigInteger SHORT_MAX = BigInteger.valueOf(Short.MAX_VALUE); 067 private static final BigInteger SHORT_MIN = BigInteger.valueOf(Short.MIN_VALUE); 068 private static final BigInteger BYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE); 069 private static final BigInteger BYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE); 070 071 /** 072 * These are eliminated / removed from any call to a method which returns either an array 073 * of Java Primitives or a Java Primitive Stream 074 * 075 * @see #intArrayToStream(JsonArray, int, int, ToIntFunction) 076 * @see #longArrayToStream(JsonArray, long, int, ToLongFunction) 077 * @see #doubleArrayToStream(JsonArray, double, int, ToDoubleFunction) 078 * @see #byteArray(JsonArray, byte, int, ToByteFunction) 079 * @see #floatArray(JsonArray, float, int, ToFloatFunction) 080 * @see #shortArray(JsonArray, short, int, ToShortFunction) 081 * @see #booleanArray(JsonArray, boolean, int, Predicate) 082 */ 083 public static final int NOT_ALLOWED_RET_NULL_MASKS = ~(RETURN_NULL_ON_ANY_ALL | 084 RETURN_NULL_ON_AEX | RETURN_NULL_ON_NULL | RETURN_NULL_ON_SPEX | RETURN_NULL_ON_STR | 085 RETURN_NULL_ON_0LEN_STR | RETURN_NULL_ON_WRONG_JSONTYPE | INSERT_NULL_ON_NON_SUBARRAY_TYPE); 086 087 088 // For "Integer", the javax.json will always return an instance of "Integer" if the JsonNumber 089 // is, indeed, a valid Integer. This doesn't work for Long - even though java.json will return 090 // an instance of boxed-type "Long" when the number is a Long because if the user has requested 091 // a LongStream, and an Integer was parsed (because the number was between 0 and MAX_INT), then 092 // just checking the Class of the returned value will fail. 093 // 094 // Converting to a returned "Integer" or "Long" to a "BigInteger" is extremely cheap, and fast, 095 // since the class BigInteger will just save the "Integer" internally. 096 097 098 private static boolean shortTypePred(JsonNumber jn) 099 { 100 if (! jn.isIntegral()) return false; 101 102 BigInteger bi = jn.bigIntegerValue(); 103 int signum = bi.signum(); 104 105 return ((signum > 0) && (bi.compareTo(SHORT_MAX) <= 0)) 106 || ((signum < 0) && (bi.compareTo(SHORT_MIN) >= 0)) 107 || (signum == 0); 108 } 109 110 private static boolean byteTypePred(JsonNumber jn) 111 { 112 if (! jn.isIntegral()) return false; 113 114 BigInteger bi = jn.bigIntegerValue(); 115 int signum = bi.signum(); 116 117 return ((signum > 0) && (bi.compareTo(BYTE_MAX) <= 0)) 118 || ((signum < 0) && (bi.compareTo(BYTE_MIN) >= 0)) 119 || (signum == 0); 120 } 121 122 private static boolean doubleTypePred(JsonNumber jn) 123 { return true; /* for now! Only bizzare & egregious cases won't fit into a double... */ } 124 125 private static boolean floatTypePred(JsonNumber jn) 126 { return true; } 127 128 private static boolean longTypePred(JsonNumber jn) 129 { 130 if (! jn.isIntegral()) return false; 131 132 BigInteger bi = jn.bigIntegerValue(); 133 int signum = bi.signum(); 134 135 return ((signum > 0) && (bi.compareTo(LONG_MAX) <= 0)) 136 || ((signum < 0) && (bi.compareTo(LONG_MIN) >= 0)) 137 || (signum == 0); 138 } 139 140 141 // ******************************************************************************************** 142 // ******************************************************************************************** 143 // HELPER-RECORD 144 // ******************************************************************************************** 145 // ******************************************************************************************** 146 147 148 // NOTE: It is **A LOT** Smarter to check for the exception instead of using the try-catch 149 // since I have read that generating an exception is one of the most costly-expensive 150 // things the JRE does. It isn't the Exception-Constructor that costs a lot - it is the 151 // creating of the **STACK-TRACE** that costs well over 100 to 1,000 times the number of 152 // of CPU-Cycles that the cost of a simple constructor. This is an "Only if abolutely" 153 // necessary things. 154 155 private static <T extends Number> ArithmeticException getAEX 156 (JsonNumber jn, Function<BigDecimal, ?> converter) 157 { 158 try 159 { converter.apply(jn.bigDecimalValue()); } 160 catch (ArithmeticException aex) 161 { return aex; } 162 163 throw new UnreachableError(); 164 } 165 166 private static Exception getSPEX(String s, Function<String, ?> converter) 167 { 168 try 169 { converter.apply(s); } 170 catch (Exception e) 171 { return e; } 172 173 throw new UnreachableError(); 174 } 175 176 177 // ******************************************************************************************** 178 // ******************************************************************************************** 179 // RECORD Configuration-Class 180 // ******************************************************************************************** 181 // ******************************************************************************************** 182 183 184 private static class RECORD<T, U> 185 { 186 // Assigned after construction, cannot be final 187 private JsonArray ja; 188 189 private final T defaultValue; 190 191 private final boolean RJA_AEX, RTS_WT, IN_NSAT, S_NSAT; 192 193 private final Runnable handlerNull, handlerAEX, handlerSPEX, handlerZLS, handlerWrongType; 194 private final ObjIntConsumer<JsonValue> handlerJsonString; 195 196 private final Class<T> CLASS; 197 private final Predicate<JsonNumber> jsonNumWillFit; 198 private final Predicate<String> validStrTester; 199 private final Function<String, T> defaultParser; 200 private final Function<Number, T> numberConverter; 201 private final Function<BigDecimal, T> numberConverterExThrow; 202 private final Function<String, T> userParser; 203 204 // NOTE: This class "RECORD" can handle the standard "Stream<T>", but it can also handle 205 // the three primitive-Stream's: IntStream, LongStream and DoubleStream. 206 // 207 // Therefore these are kept as separate function-pointers. If it weren't for those three 208 // primitive-streams, this would be completely unnecessary. YES, this class is a little 209 // hard to read. 210 211 private final Runnable c; // Stream.builder() 212 private final Consumer<T> a; // Stream.Builder.accept(T) 213 private final Supplier<U> b; // Stream.Builder.build() 214 215 216 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 217 // This is only used by the methods in the nested-class "DimN" 218 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 219 // 220 // This is not final, because it is set after the constructor. 221 // 222 // Since the user is incapable of accessing any of this, and since great care has been 223 // taken to rigorously test all of this stuff, it is basically unimportant. 224 225 private Function<JsonArray, Object> array1DGenerator = null; 226 227 228 // **************************************************************************************** 229 // **************************************************************************************** 230 // PRIMARY RECORD Constructor 231 // **************************************************************************************** 232 // **************************************************************************************** 233 234 235 private RECORD( 236 T defaultValue, 237 int FLAGS, 238 239 Class<T> CLASS, 240 Predicate<JsonNumber> jsonNumWillFit, 241 Predicate<String> validStrTester, 242 Function<String, T> defaultParser, 243 Function<Number, T> numberConverter, 244 Function<BigDecimal, T> numberConverterExThrow, 245 Function<String, T> userParser, 246 boolean NULLS, 247 248 Runnable streamConstructor, 249 Consumer<T> streamAcceptor, 250 Supplier<U> streamBuilder 251 ) 252 { 253 this.defaultValue = defaultValue; // User-Provided Default-Value 254 this.CLASS = CLASS; // Class of the Stream.Builder "accept" Parameter 255 this.jsonNumWillFit = jsonNumWillFit; // Checks if JsonNumber will fit properly 256 this.validStrTester = validStrTester; // Used for Verifying a JsonString 257 this.defaultParser = defaultParser; // Default JsonString Parser to Number 258 this.numberConverter = numberConverter; // interface java.lang.Number method 259 this.numberConverterExThrow = numberConverterExThrow; 260 this.userParser = userParser; // Optional User Parser 261 262 this.c = streamConstructor; // Stream.builder() 263 this.a = streamAcceptor; // Stream.Builder.accept() 264 this.b = streamBuilder; // Stream.Builder.build() 265 266 this.RJA_AEX = (FLAGS & RETURN_JAPPROX_ON_AEX) > 0; 267 this.RTS_WT = (FLAGS & RETURN_TOSTRING_ON_WRONGTYPE) > 0; 268 this.IN_NSAT = (FLAGS & INSERT_NULL_ON_NON_SUBARRAY_TYPE) > 0; 269 this.S_NSAT = (FLAGS & SKIP_ON_NON_SUBARRAY_TYPE) > 0; 270 271 boolean RN_AA = NULLS && ((FLAGS & RETURN_NULL_ON_ANY_ALL) > 0); 272 boolean RD_AA = (FLAGS & RETURN_DEFVAL_ON_ANY_ALL) > 0; 273 boolean S_AA = (FLAGS & SKIP_ON_ANY_ALL) > 0; 274 275 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 276 // Null Handler (JsonNull was in the JsonArray) 277 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 278 // 279 // NOTE: AN(), AD() and NOOP() are just one-line private methods that: 280 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 281 282 if (NULLS && ((FLAGS & RETURN_NULL_ON_NULL) > 0)) handlerNull = this::AN; 283 else if ((FLAGS & RETURN_DEFVAL_ON_NULL) > 0) handlerNull = this::AD; 284 else if ((FLAGS & SKIP_ON_NULL) > 0) handlerNull = this::NOOP; 285 else if (NULLS && RN_AA) handlerNull = this::AN; 286 else if (RD_AA) handlerNull = this::AD; 287 else if (S_AA) handlerNull = this::NOOP; 288 else if (NULLS) handlerNull = this::AN; 289 else handlerNull = null; 290 291 292 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 293 // AEX Handler (ArithmeticException) 294 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 295 // 296 // NOTE: AN(), AD() and NOOP() are just one-line private methods that: 297 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 298 299 if (NULLS && ((FLAGS & RETURN_NULL_ON_AEX) > 0)) handlerAEX = this::AN; 300 else if ((FLAGS & RETURN_DEFVAL_ON_AEX) > 0) handlerAEX = this::AD; 301 else if ((FLAGS & SKIP_ON_AEX) > 0) handlerAEX = this::NOOP; 302 else if (NULLS && RN_AA) handlerAEX = this::AN; 303 else if (RD_AA) handlerAEX = this::AD; 304 else if (S_AA) handlerAEX = this::NOOP; 305 else handlerAEX = null; 306 307 308 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 309 // SPEX Handler (Exception while parsing a String into the Java-Type) 310 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 311 // 312 // NOTE: AN(), AD() and NOOP() are just one-line private methods that: 313 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 314 315 if (NULLS && ((FLAGS & RETURN_NULL_ON_SPEX) > 0)) handlerSPEX = this::AN; 316 else if ((FLAGS & RETURN_DEFVAL_ON_SPEX) > 0) handlerSPEX = this::AD; 317 else if ((FLAGS & SKIP_ON_SPEX) > 0) handlerSPEX = this::NOOP; 318 else if (NULLS && RN_AA) handlerSPEX = this::AN; 319 else if (RD_AA) handlerSPEX = this::AD; 320 else if (S_AA) handlerSPEX = this::NOOP; 321 else handlerSPEX = null; 322 323 324 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 325 // ZLS Handler (A Zero-Length String was in the JsonArray) 326 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 327 // 328 // NOTE: AN(), AD() and NOOP() are just one-line private methods that: 329 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 330 331 if (NULLS && ((FLAGS & RETURN_NULL_ON_0LEN_STR) > 0)) handlerZLS = this::AN; 332 else if ((FLAGS & RETURN_DEFVAL_ON_0LEN_STR) > 0) handlerZLS = this::AD; 333 else if ((FLAGS & SKIP_ON_0LEN_STR) > 0) handlerZLS = this::NOOP; 334 else if (NULLS && RN_AA) handlerZLS = this::AN; 335 else if (RD_AA) handlerZLS = this::AD; 336 else if (S_AA) handlerZLS = this::NOOP; 337 else handlerZLS = null; 338 339 340 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 341 // Wrong-Type Handler (A JsonObject or a nested-JsonArray was in an array position) 342 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 343 // 344 // NOTE: AN(), AD() and NOOP() are just one-line private methods that: 345 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 346 // 347 // ALSO: RN_WT & RD_WT are the abbreviated-flags for "ON_WRONG_JSONTYPE" 348 349 if (NULLS && ((FLAGS & RN_WT) > 0)) handlerWrongType = this::AN; 350 else if ((FLAGS & RD_WT) > 0) handlerWrongType = this::AD; 351 else if ((FLAGS & SKIP_ON_WRONG_JSONTYPE) > 0) handlerWrongType = this::NOOP; 352 else if (NULLS && RN_AA) handlerWrongType = this::AN; 353 else if (RD_AA) handlerWrongType = this::AD; 354 else if (S_AA) handlerWrongType = this::NOOP; 355 else handlerWrongType = null; 356 357 358 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 359 // JsonString Handler (This was *ALSO* moved here to get rid of more of the if's) 360 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 361 // 362 // NOTE: AN(JsonValue, int), AD(JsonValue, int) and NOOP(JsonValue, int) are just 363 // one-line private methods that: 364 // a.accept(null), a.accept(defaultValue), and {} ==> do nothing (SKIP) 365 366 if (userParser != null) handlerJsonString = this::useUserParser; 367 else if ((FLAGS & RP_S) > 0) handlerJsonString = this::parseString; 368 else if (NULLS && ((FLAGS & RETURN_NULL_ON_STR) > 0)) handlerJsonString = this::AN; 369 else if ((FLAGS & RETURN_DEFVAL_ON_STR) > 0) handlerJsonString = this::AD; 370 else if ((FLAGS & SKIP_ON_STR) > 0) handlerJsonString = this::NOOP; 371 else if (NULLS && RN_AA) handlerJsonString = this::AN; 372 else if (RD_AA) handlerJsonString = this::AD; 373 else if (S_AA) handlerJsonString = this::NOOP; 374 else handlerJsonString = (JsonValue jv, int i) -> 375 { throw new JsonTypeArrException (this.ja, i, NUMBER, jv, this.CLASS); }; 376 } 377 378 379 // **************************************************************************************** 380 // **************************************************************************************** 381 // Boxed-Primitive Stream RECORD Contructor 382 // **************************************************************************************** 383 // **************************************************************************************** 384 385 386 @SuppressWarnings({"unchecked"}) 387 private RECORD( 388 T defaultValue, 389 int FLAGS, 390 391 Class<T> CLASS, 392 Predicate<JsonNumber> jsonNumWillFit, 393 Predicate<String> validStrTester, 394 Function<String, T> defaultParser, 395 Function<Number, T> numberConverter, 396 Function<BigDecimal, T> numberConverterExThrow, 397 Function<String, T> userParser 398 ) 399 { 400 this( 401 defaultValue, FLAGS, 402 403 CLASS, jsonNumWillFit, validStrTester, defaultParser, numberConverter, 404 numberConverterExThrow, userParser, true, 405 406 constructorHelper(new EffectivelyFinal<>(null)),//, CLASS, Stream.class), 407 (Consumer<T>) constructorHelper.b, // Un-Checked Cast 408 (Supplier<U>) constructorHelper.c // Un-Checked Cast 409 ); 410 411 // Essentially, the lock is only used for about three instructions that are inside the 412 // method "constructorHelper". It, sort-of, "borrows" a private static-field for just 413 // a moment, so that the values can be passed to the call to "this(...)", which is 414 // just "kind-of" faking out the compiler so I can do some processing before calling 415 // "this(...)" as above 416 // 417 // Now that the loan-out is over, unlock the lock, and it can be used in another call 418 419 lock.unlock(); 420 421 // THIS CLASS *IS* THREAD SAFE, 422 // THIS Nested-Class "RECORD" IS NOT THREAD-SAFE - EXCEPT THE USER IS NOT ALLOWED ACCESS, 423 // AND MAY NOT OBTAIN AN INSTNANCE OF "RECORD", so it all works just fine, even in a 424 // multi-threaded program! 425 426 /* 427 // OLD CODE - DON'T ERASE THIS, EVEN BEFORE THE LOCK, THIS WAS KIND OF UGLY 428 429 final EffectivelyFinal<Stream.Builder<T>> EFSB = new EffectivelyFinal<>(null); 430 431 this.c = () -> EFSB.f = Stream.builder(); 432 this.a = (T t) -> EFSB.f.accept(t); 433 this.b = () -> (U) EFSB.f.build(); 434 */ 435 } 436 437 // These are the "Contructor Helpers" that are mentioned at the top of this class (in the 438 // "import-statement" section). These are just here to help by-pass the Java Requirement 439 // that calls to "this(...)" and "super(...)" occur on the first line. 440 441 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 442 // This is NOT TO BE UNDERSTOOD BY MORTAL-MEN, SO DON'T ASK 443 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 444 // 445 // The **MAIN-POINT** of all this non-sense is that at **RUNTIME** (as you should know by 446 // by now) all Generic-Type Information has been erased. An instance of class Object is 447 // no different than an instance of class String, Integer or anything else. It is just a 448 // pointer to a class. 449 // 450 // This whole thing is just "Faking Out The Compiler" 451 // 452 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 453 // Mostly, I am very used to having all the fields in Class "RECORD" being declared FINAL 454 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 455 // 456 // It is very soothing to know that the constructor is "setting everything up", and the 457 // Json-Processor stuff isn't going to do anything with the configurations (because they 458 // are all declared FINAL). 459 460 private static final ReentrantLock lock = new ReentrantLock(); 461 462 @SuppressWarnings("rawtypes") 463 private static Ret3 constructorHelper; 464 465 @SuppressWarnings({"rawtypes", "unchecked"}) 466 private static Runnable constructorHelper(final EffectivelyFinal<Stream.Builder> EFSB) 467 { 468 lock.lock(); 469 470 // If you don't understand this line, oh well... 471 // 472 // This was "built" or "developed" in a step-wise fasion. 473 // There is a WHOLE-BUNCH of testing code, and it all worked. All this 'type-magic' is 474 // doing is tricking the java compiler, so I can have my way. 475 // 476 // Every time I play with the types, I go back and run a GIANT-STACK of TEST 477 // PROCEDURES. If they all work, I know this works. This is **NOT REALLY** a good 478 // software-writing practice, **HOWEVER** Java-Generics are sometimes a real problem. 479 // 480 // The purpose of having TYPES in a programming language is to help catch programming 481 // errors early-on at compile-time. Java does this pretty well, but when things get 482 // advanced (it is always with Function-Pointers - a.k.a. "Functional-Interfaces" and 483 // Lambda-Expressions)... when things get "ADVANCED" it is sometimes a little 484 // ridiculours. 485 // 486 // When they say that Java-Script is a "TYPE-LESS" language at that it is easier, well, 487 // Java-Script has tons of Run-Time errors that can be impossible to debug/find! 488 // 489 // There is no real-way that I can think of to "improve" generics, because all the are 490 // in the first-place is a little "Help Finding the Errors" at Compile-Time thing... 491 492 constructorHelper = new Ret3<Runnable, Consumer, Supplier>( 493 (Runnable) (() -> EFSB.f = Stream.builder()), 494 (Consumer) ((Object o) -> EFSB.f.accept(o)), 495 (Supplier) (() -> /*(B)*/ EFSB.f.build()) 496 ); 497 498 return (Runnable) constructorHelper.a; 499 } 500 501 502 // **************************************************************************************** 503 // **************************************************************************************** 504 // HELPER'S FOR THE HANDLERS 505 // **************************************************************************************** 506 // **************************************************************************************** 507 508 private void AN() { a.accept(null); } 509 private void AD() { a.accept(defaultValue); } 510 private void NOOP() { } 511 512 private void AN(JsonValue jv, int i) { a.accept(null); } 513 private void AD(JsonValue jv, int i) { a.accept(defaultValue); } 514 private void NOOP(JsonValue jv, int i) { } 515 516 private void useUserParser(JsonValue jv, int i) 517 { 518 try 519 { 520 this.a.accept 521 (this.userParser.apply(((JsonString) jv).getString())); 522 } 523 524 catch (Exception e) 525 { 526 if (this.handlerSPEX != null) this.handlerSPEX.run(); 527 else throw new JsonStrParseArrException(e, this.ja, i, jv, this.CLASS); 528 } 529 }; 530 531 private void parseString(JsonValue jv, int i) 532 { 533 String s = ((JsonString) jv).getString(); 534 535 if (s.length() == 0) 536 { 537 if (this.handlerZLS != null) this.handlerZLS.run(); 538 539 else throw new JsonStrParseArrException( 540 new IllegalArgumentException("Zero Length String"), 541 this.ja, i, jv, this.CLASS 542 ); 543 } 544 545 // StringParse.isInteger(s), isLong(String) **AND** s -> true (Double) 546 else if (this.validStrTester.test(s)) 547 548 // Integer.parseInt(String), Long.parseLong, Double.parseDouble 549 this.a.accept(this.defaultParser.apply(s)); 550 551 else if (this.handlerSPEX != null) this.handlerSPEX.run(); 552 553 else throw new JsonStrParseArrException 554 (getSPEX(s, this.defaultParser), this.ja, i, jv, this.CLASS); 555 } 556 557 558 // **************************************************************************************** 559 // **************************************************************************************** 560 // Static RECORD Factory/Builder Methods -- Primitive-Streams 561 // **************************************************************************************** 562 // **************************************************************************************** 563 564 565 private static RECORD<Integer, IntStream> getIntStreamRec 566 (int defaultValue, int FLAGS, ToIntFunction<String> optionalUserParser) 567 { 568 EffectivelyFinal<IntStream.Builder> EFISB = new EffectivelyFinal<>(null); 569 570 RECORD<Integer, IntStream> rec = new RECORD<>( 571 defaultValue, 572 FLAGS, 573 574 // The class of the (only) parameter to the Stream.Builder "accept" method 575 int.class, 576 577 // A simple way to test if there will be an "ArithmeticException" 578 // Somewhat "counter-intuitive", but it works great... 579 580 (JsonNumber jn) -> Integer.class == jn.numberValue().getClass(), 581 582 StringParse::isInteger, // number-string-tester 583 Integer::parseInt, // default-parser (string to int) 584 Number::intValue, // numberConverter 585 BigDecimal::intValueExact, // cause AEX (ArithmeticException) 586 587 // Parse Number-Strings (this may be null) 588 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 589 590 (optionalUserParser != null) 591 ? (String s) -> optionalUserParser.applyAsInt(s) 592 : null, 593 594 // Primitive (nulls not allowed) 595 false, 596 597 () -> EFISB.f = IntStream.builder(), // Stream.Builder constructor 598 (Integer x) -> EFISB.f.accept(x), // Builder "accept" Function-Ptr 599 () -> EFISB.f.build() // Builder "build" Function-Ptr 600 ); 601 602 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 603 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON 604 605 rec.array1DGenerator = 606 (JsonArray ja) -> jsonArrToStream(ja, rec).toArray(); 607 608 return rec; 609 } 610 611 private static RECORD<Long, LongStream> getLongStreamRec 612 (long defaultValue, int FLAGS, ToLongFunction<String> optionalUserParser) 613 { 614 EffectivelyFinal<LongStream.Builder> EFLSB = new EffectivelyFinal<>(null); 615 616 RECORD<Long, LongStream> rec = new RECORD<>( 617 defaultValue, 618 FLAGS, 619 620 long.class, // Class of the Stream.Builder "accept" Parameter 621 ReadArrJSON::longTypePred, // Checks the JsonNumber retrieved 622 StringParse::isLong, // String-tester (for parsing number-strings) 623 Long::parseLong, // default-parser (number-string to long) 624 Number::longValue, // numberConverter 625 BigDecimal::longValueExact, // Generates AEX (ArithmeticException) 626 627 // Parse Number-Strings (this may be null) 628 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 629 630 (optionalUserParser != null) 631 ? (String s) -> optionalUserParser.applyAsLong(s) 632 : null, 633 634 // Primitive (nulls not allowed) 635 false, 636 637 () -> EFLSB.f = LongStream.builder(), // Stream.Builder constructor 638 (Long x) -> EFLSB.f.accept(x), // Builder "accept" Function-Pointer 639 () -> EFLSB.f.build() // Builder "build" Function-Pointer 640 ); 641 642 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 643 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON 644 645 rec.array1DGenerator = 646 (JsonArray ja) -> jsonArrToStream(ja, rec).toArray(); 647 648 return rec; 649 } 650 651 private static RECORD<Double, DoubleStream> getDoubleStreamRec 652 (double defaultValue, int FLAGS, ToDoubleFunction<String> optionalUserParser) 653 { 654 EffectivelyFinal<DoubleStream.Builder> EFDSB = new EffectivelyFinal<>(null); 655 656 RECORD<Double, DoubleStream> rec = new RECORD<>( 657 defaultValue, 658 FLAGS, 659 660 double.class, // Stream.Builder "accept" Parameter-Class 661 ReadArrJSON::doubleTypePred, // Checks the JsonNumber retrieved 662 StringParse::isDouble, // String-tester (for parsing number-strings) 663 Double::parseDouble, // default-parser (number-string to double) 664 (Number n) -> n.doubleValue(), // numberConverter 665 666 // Generate an AEX if the "StringParse.isDouble" failed 667 (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); }, 668 669 // Parse Number-Strings (this may be null) 670 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 671 672 (optionalUserParser != null) 673 ? (String s) -> optionalUserParser.applyAsDouble(s) 674 : null, 675 676 // Primitive (nulls not allowed) 677 false, 678 679 () -> EFDSB.f = DoubleStream.builder(), // Stream.Builder constructor 680 (Double x) -> EFDSB.f.accept(x), // Builder "accept" FunctionPtr 681 () -> EFDSB.f.build() // Builder "build" FunctionPtr 682 ); 683 684 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 685 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON 686 687 rec.array1DGenerator = 688 (JsonArray ja) -> jsonArrToStream(ja, rec).toArray(); 689 690 return rec; 691 } 692 693 694 // **************************************************************************************** 695 // **************************************************************************************** 696 // Static RECORD Factory/Builder Methods -- Boxed-Primitive-Streams 697 // **************************************************************************************** 698 // **************************************************************************************** 699 700 701 private static RECORD<Integer, Stream<Integer>> getINTEGERStreamRec 702 (int defaultValue, int FLAGS, Function<String, Integer> optionalUserParser) 703 { 704 RECORD<Integer, Stream<Integer>> rec = new RECORD<>( 705 defaultValue, 706 FLAGS, 707 Integer.class, // Class of the Stream.Builder "accept" Parameter 708 (JsonNumber jn) -> jn.numberValue().getClass() == Integer.class, 709 StringParse::isInteger, // String-tester (for parsing number-strings) 710 Integer::parseInt, // default-parser (number-string to Integer) 711 Number::intValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 712 BigDecimal::intValueExact, // Generates AEX on fail 713 optionalUserParser 714 ); 715 716 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 717 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON. 718 // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 719 // primitive "int[]" array (rather than an "Integer[]"), "IntStream.toArray" is used 720 721 rec.array1DGenerator = (JsonArray ja) -> 722 jsonArrToBoxedStream(ja, rec).toArray(Integer[]::new); 723 724 return rec; 725 } 726 727 private static RECORD<Short, Stream<Short>> getSHORTStreamRec( 728 short defaultValue, int FLAGS, Function<String, Short> optionalUserParser, 729 boolean primitiveOrBoxedOutput1DArray 730 ) 731 { 732 RECORD<Short, Stream<Short>> rec = new RECORD<>( 733 defaultValue, 734 FLAGS, 735 Short.class, // Class of the Stream.Builder "accept" Parameter 736 ReadArrJSON::shortTypePred, // Checks the JsonNumber retrieved 737 StringParse::isShort, // String-tester (for parsing number-strings) 738 Short::parseShort, // default-parser (number-string to short) 739 Number::shortValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 740 BigDecimal::shortValueExact, // Generates AEX on fail 741 optionalUserParser 742 ); 743 744 // Only used by "DimN" Sub-Class. It builds the 1D arrays. Since short's do not have 745 // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be 746 // used to dispatch-build *BOTH* a short[] and a Short[] 747 748 rec.array1DGenerator = primitiveOrBoxedOutput1DArray 749 ? rec::array1DGeneratorShort 750 : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Short[]::new); 751 752 return rec; 753 } 754 755 private static RECORD<Byte, Stream<Byte>> getBYTEStreamRec( 756 byte defaultValue, int FLAGS, Function<String, Byte> optionalUserParser, 757 boolean primitiveOrBoxedOutput1DArray 758 ) 759 { 760 RECORD<Byte, Stream<Byte>> rec = new RECORD<>( 761 defaultValue, 762 FLAGS, 763 Byte.class, // Class of the Stream.Builder "accept" Parameter 764 ReadArrJSON::byteTypePred, // Checks the JsonNumber retrieved 765 StringParse::isByte, // String-tester (for parsing number-strings) 766 Byte::parseByte, // default-parser (number-string to byte) 767 Number::byteValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 768 BigDecimal::byteValueExact, // Generates AEX on fail 769 optionalUserParser 770 ); 771 772 // Only used by "DimN" Sub-Class. It builds the 1D arrays. Since short's do not have 773 // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be 774 // used to dispatch-build *BOTH* a short[] and a Short[] 775 776 rec.array1DGenerator = primitiveOrBoxedOutput1DArray 777 ? rec::array1DGeneratorByte 778 : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Byte[]::new); 779 780 return rec; 781 } 782 783 private static RECORD<Long, Stream<Long>> getLONGStreamRec 784 (long defaultValue, int FLAGS, Function<String, Long> optionalUserParser) 785 { 786 RECORD<Long, Stream<Long>> rec = new RECORD<>( 787 defaultValue, 788 FLAGS, 789 Long.class, // Class of the Stream.Builder "accept" Parameter 790 ReadArrJSON::longTypePred, // Checks the JsonNumber retrieved 791 StringParse::isLong, // String-tester (for parsing number-strings) 792 Long::parseLong, // default-parser (number-string to long) 793 Number::longValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 794 BigDecimal::longValueExact, // Generates AEX on fail 795 optionalUserParser 796 ); 797 798 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 799 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON. 800 // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 801 // primitive "long[]" array (rather than an "Long[]"), "LongStream.toArray" is used 802 803 rec.array1DGenerator = (JsonArray ja) -> 804 jsonArrToBoxedStream(ja, rec).toArray(Long[]::new); 805 806 return rec; 807 } 808 809 private static RECORD<Double, Stream<Double>> getDOUBLEStreamRec 810 (double defaultValue, int FLAGS, Function<String, Double> optionalUserParser) 811 { 812 RECORD<Double, Stream<Double>> rec = new RECORD<>( 813 defaultValue, 814 FLAGS, 815 Double.class, // Class of the Stream.Builder "accept" Parameter 816 ReadArrJSON::doubleTypePred, // Checks the JsonNumber retrieved 817 StringParse::isDouble, // String-tester (for parsing number-strings) 818 Double::parseDouble, // default-parser (number-string to double) 819 Number::doubleValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 820 (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); }, 821 optionalUserParser 822 ); 823 824 // This is used by the methods in the Nested-Class "DimN" only. It is a wrapper 825 // for the JsonArray -> JavaArray method. This is *NOT* used in ReadArrJSON. 826 // Note that this produces a Boxed-Type Array **ONLY**, if the user wants a 827 // primitive "double[]" array (rather than an "Double[]"), "DoubleStream.toArray" is 828 // used 829 830 rec.array1DGenerator = (JsonArray ja) -> 831 jsonArrToBoxedStream(ja, rec).toArray(Double[]::new); 832 833 return rec; 834 } 835 836 private static RECORD<Float, Stream<Float>> getFLOATStreamRec( 837 float defaultValue, int FLAGS, Function<String, Float> optionalUserParser, 838 boolean primitiveOrBoxedOutput1DArray 839 ) 840 { 841 RECORD<Float, Stream<Float>> rec = new RECORD<>( 842 defaultValue, 843 FLAGS, 844 Float.class, // Class of the Stream.Builder "accept" Parameter 845 ReadArrJSON::floatTypePred, // Checks the JsonNumber retrieved 846 StringParse::isDouble, // String-tester (for parsing number-strings) 847 Float::parseFloat, // default-parser (number-string to float) 848 Number::floatValue, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 849 (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); }, 850 optionalUserParser 851 ); 852 853 // Only used by "DimN" Sub-Class. It builds the 1D arrays. Since short's do not have 854 // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be 855 // used to dispatch-build *BOTH* a short[] and a Short[] 856 857 rec.array1DGenerator = primitiveOrBoxedOutput1DArray 858 ? rec::array1DGeneratorFloat 859 : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Float[]::new); 860 861 return rec; 862 } 863 864 private static RECORD<Boolean, Stream<Boolean>> getBOOLEANStreamRec( 865 boolean defaultValue, int FLAGS, Function<String, Boolean> optionalUserParser, 866 boolean primitiveOrBoxedOutput1DArray 867 ) 868 { 869 RECORD<Boolean, Stream<Boolean>> rec = new RECORD<>( 870 defaultValue, 871 FLAGS, 872 Boolean.class, // Class of the Stream.Builder "accept" Parameter 873 null, // Checks the JsonNumber retrieved 874 s -> true, // String-tester (for parsing number-strings) 875 Boolean::parseBoolean, // default-parser (number-string to float) 876 null, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 877 null, 878 optionalUserParser 879 ); 880 881 // Only used by "DimN" Sub-Class. It builds the 1D arrays. Since short's do not have 882 // a "BoxedStream" (and ergo, do not have a ShortStream.toArray method), this must be 883 // used to dispatch-build *BOTH* a short[] and a Short[] 884 885 rec.array1DGenerator = primitiveOrBoxedOutput1DArray 886 ? rec::array1DGeneratorBoolean 887 : (JsonArray ja) -> jsonArrToBoxedStream(ja, rec).toArray(Boolean[]::new); 888 889 return rec; 890 } 891 892 private static RECORD<Number, Stream<Number>> getNumberStreamRec 893 (Number defaultValue, int FLAGS, Function<String, Number> optionalUserParser) 894 { 895 RECORD<Number, Stream<Number>> rec = new RECORD<>( 896 defaultValue, 897 FLAGS, 898 Number.class, // Class of the Stream.Builder "accept" Parameter 899 (JsonNumber jn) -> true, // Checks the JsonNumber retrieved 900 StringParse::isDouble, // String-tester (for parsing number-strings) 901 Float::parseFloat, // default-parser (number-string to float) 902 (Number n) -> n, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 903 (BigDecimal bd) -> { throw new ArithmeticException("Invalid Input"); }, 904 optionalUserParser 905 ); 906 907 rec.array1DGenerator = (JsonArray ja) -> 908 jsonArrToBoxedStream(ja, rec).toArray(Number[]::new); 909 910 return rec; 911 } 912 913 914 // **************************************************************************************** 915 // **************************************************************************************** 916 // Static RECORD Factory/Builder Methods -- Other-Streams 917 // **************************************************************************************** 918 // **************************************************************************************** 919 920 921 private static RECORD<String, Stream<String>> 922 getStringStreamRec(String defaultValue, int FLAGS) 923 { 924 RECORD<String, Stream<String>> rec = new RECORD<String, Stream<String>> ( 925 defaultValue, 926 FLAGS, 927 String.class, // Class of the Stream.Builder "accept" Parameter 928 null, // Checks the JsonNumber retrieved 929 null, // String-tester (for parsing number-strings) 930 null, // default-parser (number-string to float) 931 null, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 932 null, // Generates AEX on fail 933 null // optionalUserParser 934 ); 935 936 rec.array1DGenerator = (JsonArray ja) -> 937 strArrayToStreamINTERNAL(ja, rec).toArray(String[]::new); 938 939 return rec; 940 } 941 942 @SuppressWarnings("unchecked") // Array.newInstance returns "Object" not 943 private static <X> RECORD<X, Stream<X>> 944 getObjectStreamRec(X defaultValue, int FLAGS, Class<X> returnClass) 945 { 946 RECORD<X, Stream<X>> rec = new RECORD<>( 947 defaultValue, 948 FLAGS, 949 returnClass, // Class of the Stream.Builder "accept" Parameter 950 null, // Checks the JsonNumber retrieved 951 null, // String-tester (for parsing number-strings) 952 null, // default-parser (number-string to float) 953 null, // numberConverter (JAPPROX_ON_AEX *AND* usual-ans) 954 null, 955 null // optionalUserParser 956 ); 957 958 rec.array1DGenerator = (JsonArray ja) -> 959 objArrayToStreamINTERNAL(ja, rec).toArray 960 ((int length) -> (X[]) Array.newInstance(returnClass, length)); 961 962 return rec; 963 } 964 965 966 // **************************************************************************************** 967 // **************************************************************************************** 968 // Static RECORD Factory/Builder ==> HELPERS FOR THE FACTORY-METHODS 969 // **************************************************************************************** 970 // **************************************************************************************** 971 // 972 // REMEMBER: The 1-D Arrays ==> int[], long[], double[] are built directly from a 973 // PrimitiveStream using PrimStream.toArray, they don't need a "helper" 974 975 976 // This method is only used if the input was "Short", so it is actually not "Unchecked" 977 // but the Java-Compiler isn't smart enough to see that. 978 @SuppressWarnings("unchecked") 979 private short[] array1DGeneratorShort(JsonArray ja) 980 { 981 short[] retArrShort = new short[ja.size()]; 982 983 return boxedStreamToPrimitiveArray( 984 jsonArrToBoxedStream(ja, (RECORD<Short, Stream<Short>>) this), 985 ja, 986 short.class, 987 (Short s, int i) -> retArrShort[i] = s.shortValue(), 988 retArrShort 989 ); 990 } 991 992 // This method is only used if the input was "Byte", so it is actually not "Unchecked" 993 // but the Java-Compiler isn't smart enough to see that. 994 @SuppressWarnings("unchecked") 995 private byte[] array1DGeneratorByte(JsonArray ja) 996 { 997 byte[] retArrByte = new byte[ja.size()]; 998 999 return boxedStreamToPrimitiveArray( 1000 jsonArrToBoxedStream(ja, (RECORD<Byte, Stream<Byte>>) this), 1001 ja, 1002 byte.class, 1003 (Byte s, int i) -> retArrByte[i] = s.byteValue(), 1004 retArrByte 1005 ); 1006 } 1007 1008 // This method is only used if the input was "Float", so it is actually not "Unchecked" 1009 // but the Java-Compiler isn't smart enough to see that. 1010 @SuppressWarnings("unchecked") 1011 private float[] array1DGeneratorFloat(JsonArray ja) 1012 { 1013 float[] retArrFloat = new float[ja.size()]; 1014 1015 return boxedStreamToPrimitiveArray( 1016 jsonArrToBoxedStream(ja, (RECORD<Float, Stream<Float>>) this), 1017 ja, 1018 float.class, 1019 (Float s, int i) -> retArrFloat[i] = s.floatValue(), 1020 retArrFloat 1021 ); 1022 } 1023 1024 // This method is only used if the input was "Boolean", so it is actually not "Unchecked" 1025 // but the Java-Compiler isn't smart enough to see that. 1026 @SuppressWarnings("unchecked") 1027 private boolean[] array1DGeneratorBoolean(JsonArray ja) 1028 { 1029 boolean[] retArrBoolean = new boolean[ja.size()]; 1030 1031 return boxedStreamToPrimitiveArray( 1032 booleanArrayToBoxedStreamINTERNAL 1033 (ja, (RECORD<Boolean, Stream<Boolean>>) this), 1034 ja, 1035 boolean.class, 1036 (Boolean s, int i) -> retArrBoolean[i] = s.booleanValue(), 1037 retArrBoolean 1038 ); 1039 } 1040 } 1041 1042 1043 // ******************************************************************************************** 1044 // ******************************************************************************************** 1045 // PRIMARY CONVERTER FOR THREE STREAM FUNCTIONS 1046 // ******************************************************************************************** 1047 // ******************************************************************************************** 1048 // 1049 // NOTE: There is just no-way to document this damned thing. *ALL IT IS DOING* is telling you 1050 // that a Json-Array like [3, 4, 5] maps to a Java-Array like [3, 4, 5]. The extra 1051 // work is checking for things like ["3", 4, 5] (where the 3 is a String), since this 1052 // is completely legal in JSON, but not Java. AND ALSO: [3.0, 4.1, 5.2] can be mapped 1053 // to [3, 4, 5] - if and only if the FLAGS are properly set by the user... 1054 // 1055 // The whole value of this is the error-checking, and the ability to TIGHTEN AND RELAX the 1056 // requirements. It makes using a REST-API (which communicates with the outside world using 1057 // JSON), a whole bunch of ONE-LINE statments. (This HELPS a lot, but it is so AWFUL to look 1058 // at) 1059 1060 /** 1061 * Builds a Primitive-Stream from a {@link JsonArray} 1062 * 1063 * @param ja The {@link JsonArray} 1064 * @param rec The configurations 1065 * 1066 * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' 1067 * DATA-FILE-ID=RARR_PS_JNPAEX> 1068 * 1069 * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JAAEX> 1070 * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JSPAEX> 1071 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_PS_JTAEX> 1072 */ 1073 protected static <T, U> U jsonArrToStream(JsonArray ja, RECORD<T, U> rec) 1074 { 1075 rec.ja = ja; 1076 rec.c.run(); // Construct a new Stream-Builder 1077 1078 int SIZE = ja.size(); 1079 JsonValue jv; 1080 1081 for (int i=0; i < SIZE; i++) 1082 1083 switch ((jv = ja.get(i)).getValueType()) 1084 { 1085 // javax.json.JsonValue.ValueType.NULL 1086 case NULL: 1087 if (rec.handlerNull != null) rec.handlerNull.run(); 1088 else throw new JsonNullPrimitiveArrException(ja, i, NUMBER, rec.CLASS); 1089 break; 1090 1091 // javax.json.JsonValue.ValueType.NUMBER 1092 case NUMBER: 1093 1094 JsonNumber jn = (JsonNumber) jv; 1095 1096 // Guaranteed to work properly ==> This is the "definition of RJA_AEX" 1097 // 1098 // "numberConverter" is just Number.intValue, longValue, doubleValue 1099 // Number.intValue(), longValue(), doubleValue() **DO NOT** throw any 1100 // exceptions. They round (if necessary), or return MAX_INT, MAX_LONG, etc... 1101 // (also, only if necessary) 1102 1103 if (rec.RJA_AEX || rec.jsonNumWillFit.test(jn)) 1104 rec.a.accept(rec.numberConverter.apply(jn.numberValue())); 1105 1106 else if (rec.handlerAEX != null) rec.handlerAEX.run(); 1107 1108 else throw new JsonArithmeticArrException 1109 (getAEX(jn, rec.numberConverterExThrow), ja, i, NUMBER, jv, rec.CLASS); 1110 1111 break; 1112 1113 // javax.json.JsonValue.ValueType.STRING 1114 case STRING: rec.handlerJsonString.accept(jv, i); break; 1115 1116 // javax.json.JsonValue.ValueType.TRUE, FALSE, ARRAY, OBJECT 1117 default: 1118 if (rec.handlerWrongType != null) rec.handlerWrongType.run(); 1119 else throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS); 1120 } 1121 1122 // Run Stream.Builder.build(); 1123 return rec.b.get(); 1124 } 1125 1126 1127 // ******************************************************************************************** 1128 // ******************************************************************************************** 1129 // THREE JSON-ARRAY ==> JAVA-STREAM METHODS (int-stream, double-stream, long-stream) 1130 // ******************************************************************************************** 1131 // ******************************************************************************************** 1132 1133 1134 /** 1135 * Convenience Method. 1136 * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)} 1137 * <BR />Passes: Java {@code IntStream} Configurtion-Record 1138 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream 1139 * <BR />For information about the {@link JFlag} parameter, click the method link above. 1140 * 1141 * <BR /><BR />Producing a standard java {@code int[]} array from an {@code IntStream} is a 1142 * trivial-converstion: 1143 * 1144 * <DIV CLASS=LOC>{@code 1145 * int[] arr = intArrayToStream(ja, -1, 0, null).toArray(); 1146 * }</DIV> 1147 */ 1148 public static IntStream intArrayToStream 1149 (JsonArray ja, int defaultValue, int FLAGS, ToIntFunction<String> optionalUserParser) 1150 { 1151 return jsonArrToStream( 1152 ja, RECORD.getIntStreamRec 1153 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser) 1154 ); 1155 } 1156 1157 /** 1158 * Convenience Method. 1159 * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)} 1160 * <BR />Passes: Java {@code LongStream} Configurtion-Record 1161 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream 1162 * <BR />For information about the {@link JFlag} parameter, click the method link above. 1163 * 1164 * <BR /><BR />Producing a standard java {@code long[]} array from a {@code LongStream} is a 1165 * trivial-converstion: 1166 * 1167 * <DIV CLASS=LOC>{@code 1168 * long[] arr = longArrayToStream(ja, -1, 0, null).toArray(); 1169 * }</DIV> 1170 */ 1171 public static LongStream longArrayToStream 1172 (JsonArray ja, long defaultValue, int FLAGS, ToLongFunction<String> optionalUserParser) 1173 { 1174 return jsonArrToStream( 1175 ja, RECORD.getLongStreamRec 1176 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser) 1177 ); 1178 } 1179 1180 /** 1181 * Convenience Method. 1182 * <BR />Invokes: {@link #jsonArrToStream(JsonArray, RECORD)} 1183 * <BR />Passes: Java {@code DoubleStream} Configurtion-Record 1184 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-stream 1185 * <BR />For information about the {@link JFlag} parameter, click the method link above. 1186 * 1187 * <BR /><BR />Producing a standard java {@code double[]} array from a {@code DoubleStream} is 1188 * a trivial-converstion: 1189 * 1190 * <DIV CLASS=LOC>{@code 1191 * double[] arr = doubleArrayToStream(ja, -1, 0, null).toArray(); 1192 * }</DIV> 1193 */ 1194 public static DoubleStream doubleArrayToStream 1195 (JsonArray ja, double defaultValue, int FLAGS, ToDoubleFunction<String> optionalUserParser) 1196 { 1197 return jsonArrToStream( 1198 ja, RECORD.getDoubleStreamRec 1199 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser) 1200 ); 1201 } 1202 1203 1204 // ******************************************************************************************** 1205 // ******************************************************************************************** 1206 // PRIMARY CONVERTER FOR STREAM OF BOXED-TYPES 1207 // ******************************************************************************************** 1208 // ******************************************************************************************** 1209 1210 1211 /** 1212 * Builds a Stream of Boxed-Type Numbers from a {@link JsonArray} 1213 * @param rec The configurations 1214 * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' 1215 * DATA-FILE-ID=RARR_BS_JNPAEX> 1216 * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JAAEX> 1217 * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JSPAEX> 1218 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JTAEX> 1219 */ 1220 protected static <T, U> U jsonArrToBoxedStream(JsonArray ja, RECORD<T, U> rec) 1221 { 1222 rec.c.run(); // Construct a new Stream-Builder 1223 rec.ja = ja; 1224 1225 int SIZE = ja.size(); 1226 JsonValue jv; 1227 1228 for (int i=0; i < SIZE; i++) 1229 1230 switch ((jv = ja.get(i)).getValueType()) 1231 { 1232 // javax.json.JsonValue.ValueType.NULL 1233 case NULL: rec.handlerNull.run(); break; 1234 1235 // javax.json.JsonValue.ValueType.NUMBER 1236 case NUMBER: 1237 1238 JsonNumber jn = (JsonNumber) jv; 1239 1240 // Guaranteed to work properly ==> This is the "definition of RJA_AEX" 1241 // 1242 // Number.intValue(), longValue(), doubleValue() **DO NOT** throw any 1243 // exceptions. They round (if necessary), or return MAX_INT, MAX_LONG, etc... 1244 // (also, only if necessary) 1245 1246 if (rec.RJA_AEX || rec.jsonNumWillFit.test(jn)) 1247 rec.a.accept(rec.numberConverter.apply(jn.numberValue())); 1248 1249 else if (rec.handlerAEX != null) rec.handlerAEX.run(); 1250 1251 else throw new JsonArithmeticArrException 1252 (getAEX(jn, rec.numberConverterExThrow), ja, i, NUMBER, jv, rec.CLASS); 1253 1254 break; 1255 1256 // javax.json.JsonValue.ValueType.STRING 1257 case STRING: rec.handlerJsonString.accept(jv, i); break; 1258 1259 // OBJECT, ARRAY, TRUE, FALSE 1260 default: 1261 if (rec.handlerWrongType != null) rec.handlerWrongType.run(); 1262 else throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS); 1263 } 1264 1265 // Run Stream.Builder.build() 1266 return rec.b.get(); 1267 } 1268 1269 1270 // ******************************************************************************************** 1271 // ******************************************************************************************** 1272 // Json-Array to Java Arrays of Primitives 1273 // ******************************************************************************************** 1274 // ******************************************************************************************** 1275 1276 1277 /** 1278 * Converts a Java Boxed Stream to a Primitive Array. 1279 * @param <T> The generic-type of the {@code java.util.stream.Stream} 1280 * @param <U> The returned primitive-array type 1281 * @param boxedStream A Java Boxed Stream 1282 * @param arrayBuilder A consumer which inserts a Boxed-Number into the Primitive-Array 1283 * @param ja The {@link JsonArray} that generated the Boxed-Stream. Needed for error-output 1284 * @param returnClass The {@code java.lang.Class} (generic-type parameter) for the 1285 * {@code Stream}. In other words, the {@code Class} for type-parameter {@code <T>}. 1286 * This is only needed if there is an exception, for proper & readable error-reporting. 1287 */ 1288 protected static <T, U> U boxedStreamToPrimitiveArray( 1289 Stream<T> boxedStream, 1290 JsonArray ja, 1291 Class<T> returnClass, 1292 ObjIntConsumer<T> arrayBuilder, 1293 U retArr 1294 ) 1295 { 1296 // Since the array-index is used inside of a LAMBDA, this "EffectivelyFinal" counter 1297 // class becomes necessary. 1298 1299 Counter counter = new Counter(-1); 1300 1301 // Don't forget, Stream's are not guaranteed to be processed in order, unless an 1302 // explicit request is made using something like 'forEachOrdered' 1303 1304 boxedStream.forEachOrdered((T boxedPrimitive) -> 1305 { 1306 int i = counter.addOne(); // "Final, or Effectively Final" 1307 1308 // A Primitive-Array (like int[], long[], boolean[] etc...) may not have null 1309 if (boxedPrimitive == null) 1310 throw new JsonNullPrimitiveArrException(ja, i, NUMBER, returnClass); 1311 1312 // The 'arrayBuilder' just assigns the value to the array[i] 1313 arrayBuilder.accept(boxedPrimitive, i); 1314 }); 1315 1316 return retArr; 1317 } 1318 1319 /** 1320 * Convenience Method. 1321 * <BR />Invokes: {@link #shortArrayToBoxedStream(JsonArray, short, int, Function)} 1322 * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer, 1323 * Object)} 1324 * <BR /> 1325 * <BR />Converts: {@link JsonArray} to {@code Stream<Short>} and then to {@code short[]} 1326 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array 1327 * <BR /> 1328 * <BR />For information about using {@code FLAGS}, see: 1329 * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B> 1330 */ 1331 public static short[] shortArray 1332 (JsonArray ja, short defaultValue, int FLAGS, ToShortFunction<String> optionalUserParser) 1333 { 1334 short[] retArr = new short[ja.size()]; 1335 1336 return boxedStreamToPrimitiveArray( 1337 shortArrayToBoxedStream( 1338 // If there are any "Return null if..." JFlag's, they are eliminated 1339 ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 1340 1341 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 1342 (optionalUserParser != null) 1343 ? (String s) -> optionalUserParser.applyAsShort(s) 1344 : null 1345 ), 1346 ja, 1347 short.class, 1348 (Short s, int i) -> retArr[i] = s.shortValue(), 1349 retArr 1350 ); 1351 } 1352 1353 /** 1354 * Convenience Method. 1355 * <BR />Invokes: {@link #byteArrayToBoxedStream(JsonArray, byte, int, Function)} 1356 * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer, 1357 * Object)} 1358 * <BR /> 1359 * <BR />Converts: {@link JsonArray} to {@code Stream<Byte>} and then to {@code byte[]} 1360 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array 1361 * <BR /> 1362 * <BR />For information about using {@code FLAGS}, see: 1363 * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B> 1364 */ 1365 public static byte[] byteArray 1366 (JsonArray ja, byte defaultValue, int FLAGS, ToByteFunction<String> optionalUserParser) 1367 { 1368 byte[] retArr = new byte[ja.size()]; 1369 1370 return boxedStreamToPrimitiveArray( 1371 byteArrayToBoxedStream( 1372 // If there are any "Return null if..." JFlag's, they are eliminated 1373 ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 1374 1375 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 1376 (optionalUserParser != null) 1377 ? (String s) -> optionalUserParser.applyAsByte(s) 1378 : null 1379 ), 1380 ja, 1381 byte.class, 1382 (Byte s, int i) -> retArr[i] = s.byteValue(), 1383 retArr 1384 ); 1385 } 1386 1387 /** 1388 * Convenience Method. 1389 * <BR />Invokes: {@link #floatArrayToBoxedStream(JsonArray, float, int, Function)} 1390 * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer, 1391 * Object)} 1392 * <BR /> 1393 * <BR />Converts: {@link JsonArray} to {@code Stream<Float>} and then to {@code float[]} 1394 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array 1395 * <BR /> 1396 * <BR />For information about using {@code FLAGS}, see: 1397 * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B> 1398 */ 1399 public static float[] floatArray 1400 (JsonArray ja, float defaultValue, int FLAGS, ToFloatFunction<String> optionalUserParser) 1401 { 1402 float[] retArr = new float[ja.size()]; 1403 1404 return boxedStreamToPrimitiveArray( 1405 floatArrayToBoxedStream( 1406 // If there are any "Return null if..." JFlag's, they are eliminated 1407 ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 1408 1409 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 1410 (optionalUserParser != null) 1411 ? (String s) -> optionalUserParser.applyAsFloat(s) 1412 : null 1413 ), 1414 ja, 1415 float.class, 1416 (Float s, int i) -> retArr[i] = s.floatValue(), 1417 retArr 1418 ); 1419 } 1420 1421 /** 1422 * Convenience Method. 1423 * <BR />Invokes: {@link #booleanArrayToBoxedStream(JsonArray, boolean, int, Function)} 1424 * <BR />And: {@link #boxedStreamToPrimitiveArray(Stream, JsonArray, Class, ObjIntConsumer, 1425 * Object)} 1426 * <BR /> 1427 * <BR />Converts: {@link JsonArray} to {@code Stream<Boolean>} and then to {@code boolean[]} 1428 * <BR />Removes: Any {@link JFlag} masks which might insert null-entries in the return-array 1429 * <BR /> 1430 * <BR />For information about using {@code FLAGS}, see: 1431 * <B>{@link #jsonArrToBoxedStream(JsonArray, RECORD)}</B> 1432 */ 1433 public static boolean[] booleanArray( 1434 JsonArray ja, boolean defaultValue, int FLAGS, 1435 Predicate<String> optionalUserParser 1436 ) 1437 { 1438 boolean[] retArr = new boolean[ja.size()]; 1439 1440 return boxedStreamToPrimitiveArray( 1441 booleanArrayToBoxedStream( 1442 // If there are any "Return null if...", they are eliminated 1443 ja, defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 1444 1445 // IMPORTANT, If the user didn't pass a parser, it is imperative that this is null! 1446 (optionalUserParser != null) ? (String s) -> optionalUserParser.test(s) : null 1447 ), 1448 ja, 1449 boolean.class, 1450 (Boolean s, int i) -> retArr[i] = s.booleanValue(), 1451 retArr 1452 ); 1453 } 1454 1455 1456 // ******************************************************************************************** 1457 // ******************************************************************************************** 1458 // Json-Array to Stream of Boxed-Number Types 1459 // ******************************************************************************************** 1460 // ******************************************************************************************** 1461 1462 1463 /** 1464 * Convenience Method. 1465 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1466 * <BR />Fills in Configuration Record for Integer-Retrieval 1467 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1468 * <BR /> 1469 * <BR />Producing a Boxed-Integer Array from this Method is as Follows: 1470 * <DIV CLASS=LOC>{@code 1471 * Integer[] arr = integerArrayToBoxedStream(ja, -1, 0 null).toArray(Integer[]::new); 1472 * }</DIV> 1473 */ 1474 public static Stream<Integer> integerArrayToBoxedStream 1475 (JsonArray ja, int defaultValue, int FLAGS, Function<String, Integer> optionalUserParser) 1476 { 1477 return jsonArrToBoxedStream 1478 (ja, RECORD.getINTEGERStreamRec(defaultValue, FLAGS, optionalUserParser)); 1479 } 1480 1481 /** 1482 * Convenience Method. 1483 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1484 * <BR />Fills in Configuration Record for Short-Retrieval 1485 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1486 * <BR /> 1487 * <BR />Producing a Boxed-Short Array from this Method is as Follows: 1488 * <DIV CLASS=LOC>{@code 1489 * Short[] arr = shortArrayToBoxedStream(ja, -1, 0 null).toArray(Short[]::new); 1490 * }</DIV> 1491 */ 1492 public static Stream<Short> shortArrayToBoxedStream 1493 (JsonArray ja, short defaultValue, int FLAGS, Function<String, Short> optionalUserParser) 1494 { 1495 return jsonArrToBoxedStream 1496 (ja, RECORD.getSHORTStreamRec(defaultValue, FLAGS, optionalUserParser, false)); 1497 } 1498 1499 /** 1500 * Convenience Method. 1501 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1502 * <BR />Fills in Configuration Record for Byte-Retrieval 1503 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1504 * <BR /> 1505 * <BR />Producing a Boxed-Byte Array from this Method is as Follows: 1506 * <DIV CLASS=LOC>{@code 1507 * Byte[] arr = byteArrayToBoxedStream(ja, -1, 0 null).toArray(Byte[]::new); 1508 * }</DIV> 1509 */ 1510 public static Stream<Byte> byteArrayToBoxedStream 1511 (JsonArray ja, byte defaultValue, int FLAGS, Function<String, Byte> optionalUserParser) 1512 { 1513 return jsonArrToBoxedStream 1514 (ja, RECORD.getBYTEStreamRec(defaultValue, FLAGS, optionalUserParser, false)); 1515 } 1516 1517 /** 1518 * Convenience Method. 1519 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1520 * <BR />Fills in Configuration Record for Long-Retrieval 1521 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1522 * <BR /> 1523 * <BR />Producing a Boxed-Long Array from this Method is as Follows: 1524 * <DIV CLASS=LOC>{@code 1525 * Long[] arr = longArrayToBoxedStream(ja, -1, 0 null).toArray(Long[]::new); 1526 * }</DIV> 1527 */ 1528 public static Stream<Long> longArrayToBoxedStream 1529 (JsonArray ja, long defaultValue, int FLAGS, Function<String, Long> optionalUserParser) 1530 { 1531 return jsonArrToBoxedStream 1532 (ja, RECORD.getLONGStreamRec(defaultValue, FLAGS, optionalUserParser)); 1533 } 1534 1535 /** 1536 * Convenience Method. 1537 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1538 * <BR />Fills in Configuration Record for Double-Retrieval 1539 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1540 * <BR /> 1541 * <BR />Producing a Boxed-Double Array from this Method is as Follows: 1542 * <DIV CLASS=LOC>{@code 1543 * Double[] arr = doubleArrayToBoxedStream(ja, -1, 0 null).toArray(Double[]::new); 1544 * }</DIV> 1545 */ 1546 public static Stream<Double> doubleArrayToBoxedStream 1547 (JsonArray ja, double defaultValue, int FLAGS, Function<String, Double> optionalUserParser) 1548 { 1549 return jsonArrToBoxedStream 1550 (ja, RECORD.getDOUBLEStreamRec(defaultValue, FLAGS, optionalUserParser)); 1551 } 1552 1553 /** 1554 * Convenience Method. 1555 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1556 * <BR />Fills in Configuration Record for Float-Retrieval 1557 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1558 * <BR /> 1559 * <BR />Producing a Boxed-Float Array from this Method is as Follows: 1560 * <DIV CLASS=LOC>{@code 1561 * Float[] arr = floatArrayToBoxedStream(ja, -1, 0 null).toArray(Float[]::new); 1562 * }</DIV> 1563 */ 1564 public static Stream<Float> floatArrayToBoxedStream 1565 (JsonArray ja, float defaultValue, int FLAGS, Function<String, Float> optionalUserParser) 1566 { 1567 return jsonArrToBoxedStream 1568 (ja, RECORD.getFLOATStreamRec(defaultValue, FLAGS, optionalUserParser, false)); 1569 } 1570 1571 /** 1572 * Convenience Method. 1573 * <BR />Invokes: {@link #jsonArrToBoxedStream(JsonArray, RECORD)} 1574 * <BR />Fills in Configuration Record for Number-Retrieval 1575 * <BR />For more Information about the {@link JFlag} Parameter, Click the Method-Link above. 1576 * <BR /> 1577 * <BR />Producing a Boxed-Number Array from this Method is as Follows: 1578 * <DIV CLASS=LOC>{@code 1579 * Number[] arr = numberArrayToBoxedStream(ja, -1, 0 null).toArray(Number[]::new); 1580 * }</DIV> 1581 */ 1582 public static Stream<Number> numberArrayToBoxedStream 1583 (JsonArray ja, Number defaultValue, int FLAGS, Function<String, Number> optionalUserParser) 1584 { 1585 return jsonArrToBoxedStream 1586 (ja, RECORD.getNumberStreamRec(defaultValue, FLAGS, optionalUserParser)); 1587 } 1588 1589 1590 // ******************************************************************************************** 1591 // ******************************************************************************************** 1592 // More Types 1593 // ******************************************************************************************** 1594 // ******************************************************************************************** 1595 1596 1597 /** 1598 * Converts a {@link JsonArray} into a {@code Stream<String>}. A Java {@code Stream<String>} 1599 * is easily converted to a {@code String[]}-Array via a call to: 1600 * 1601 * <DIV CLASS=LOC>{@code 1602 * String[] sArr = strArrayToStream(myJsonArray, null, 0).toArray(String[]::new); 1603 * }</DIV> 1604 * 1605 * @param ja Any {@code JsonArray}, but preferrably one which contains instances of 1606 * {@link JsonString} 1607 * 1608 * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be 1609 * inserted into the output-array when error cases occur at particular array-index locations. 1610 * 1611 * @param FLAGS Optional flags. See {@link JFlag} for details. 1612 * 1613 * @return A Java {@code Stream<String>}. 1614 */ 1615 public static Stream<String> strArrayToStream(JsonArray ja, String defaultValue, int FLAGS) 1616 { return strArrayToStreamINTERNAL(ja, RECORD.getStringStreamRec(defaultValue, FLAGS)); } 1617 1618 private static Stream<String> strArrayToStreamINTERNAL 1619 (JsonArray ja, RECORD<String, Stream<String>> rec) 1620 { 1621 int SIZE = ja.size(); 1622 JsonValue jv = null; 1623 1624 rec.c.run(); // Construct a new Stream-Builder 1625 rec.ja = ja; 1626 1627 for (int i=0; i < SIZE; i++) 1628 1629 switch ((jv = ja.get(i)).getValueType()) 1630 { 1631 // javax.json.JsonValue.ValueType.NULL 1632 case NULL: rec.handlerNull.run(); break; 1633 1634 // javax.json.JsonValue.ValueType.STRING 1635 case STRING: rec.a.accept(((JsonString) jv).getString()); break; 1636 1637 // OBJECT, ARRAY, TRUE, FALSE, NUMBER 1638 default: 1639 1640 if (rec.RTS_WT) rec.a.accept(jv.toString()); 1641 1642 else if (rec.handlerWrongType != null) rec.handlerWrongType.run(); 1643 1644 else throw new JsonTypeArrException(ja, i, STRING, jv, String.class); 1645 } 1646 1647 // Run Stream.Builder.build() 1648 return rec.b.get(); 1649 } 1650 1651 /** 1652 * Converts a {@link JsonArray} into a {@code Stream<Boolean>}. A Java {@code Stream<Boolean>} 1653 * is easily converted to a {@code Boolean[]}-Array via a call to the lines below. Note that 1654 * in this example, the return array is an array of {@code Boolean} objects; it is not a 1655 * primitive {@code boolean[]} array. (To parse into a primitive array, use 1656 * {@link #booleanArray(JsonArray, boolean, int, Predicate)}) 1657 * 1658 * <DIV CLASS=LOC>{@code 1659 * Boolean[] bArr = booleanArrayToBoxedStream(myJsonArray, false, 0, null) 1660 * .toArray(Boolean[]::new); 1661 * }</DIV> 1662 * 1663 * @param ja Any {@code JsonArray}, but preferrably one which contains instances of 1664 * {@link JsonValue#TRUE} or {@link JsonValue#FALSE} 1665 * 1666 * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be 1667 * inserted into the output-array when error cases occur at particular array-index locations. 1668 * 1669 * @param FLAGS Optional flags. See {@link JFlag} for details. 1670 * 1671 * @param optionalUserParser If the appropriate flags are set, if a {@link JsonString} is 1672 * encountered while processing the {@code JsonArray}, an attempt to parse the {@code String} 1673 * into a {@code Boolean} will be made using this {@code String}-parser. 1674 * 1675 * @return A Java {@code Stream<Boolean>}. 1676 */ 1677 public static Stream<Boolean> booleanArrayToBoxedStream( 1678 JsonArray ja, boolean defaultValue, int FLAGS, 1679 Function<String, Boolean> optionalUserParser 1680 ) 1681 { 1682 return booleanArrayToBoxedStreamINTERNAL( 1683 ja, 1684 RECORD.getBOOLEANStreamRec 1685 (defaultValue, FLAGS, optionalUserParser, false) 1686 ); 1687 } 1688 1689 private static Stream<Boolean> booleanArrayToBoxedStreamINTERNAL 1690 (JsonArray ja, RECORD<Boolean, Stream<Boolean>> rec) 1691 { 1692 int SIZE = ja.size(); 1693 JsonValue jv = null; 1694 1695 rec.c.run(); // Construct a new Stream-Builder 1696 rec.ja = ja; 1697 1698 for (int i=0; i < SIZE; i++) 1699 1700 switch ((jv = ja.get(i)).getValueType()) 1701 { 1702 case NULL: rec.handlerNull.run(); break; 1703 case TRUE: rec.a.accept(true); break; 1704 case FALSE: rec.a.accept(false); break; 1705 case STRING: rec.handlerJsonString.accept(jv, i); break; 1706 1707 // javax.json.JsonValue.ValueType.NUMBER, OBJECT, ARRAY 1708 default: 1709 if (rec.handlerWrongType != null) rec.handlerWrongType.run(); 1710 else throw new JsonTypeArrException(ja, i, TRUE, jv, Boolean.class); 1711 } 1712 1713 // Run Stream.Builder.build() 1714 return rec.b.get(); 1715 } 1716 1717 /** 1718 * Converts a {@link JsonArray} into a {@code Stream<T>}. A Java {@code Stream<T>} 1719 * is easily converted to a {@code T[]}-Array via a call to the line below. 1720 * 1721 * <DIV CLASS=LOC>{@code 1722 * MyClass[] bArr = objArrayToStream(myJsonArray, null, 0, MyClass.class) 1723 * .toArray(MyClass[]::new); 1724 * }</DIV> 1725 * 1726 * @param <T> This is the 'type' of the array being built. If there were a class, for example, 1727 * named class {@code 'Automobile'}, the value passed to parameter {@code 'returnClass'} would 1728 * simply be {@code Automobile.class}. 1729 * 1730 * @param ja Any {@code JsonArray}, but preferrably one which contains instances of 1731 * {@link JsonValue#TRUE} or {@link JsonValue#FALSE} 1732 * 1733 * @param defaultValue When used in conjunction with {@code 'FLAGS'}, this default-value may be 1734 * inserted into the output-array when error cases occur at particular array-index locations. 1735 * 1736 * @param FLAGS Optional flags. See {@link JFlag} for details. 1737 * 1738 * @param returnClass The {@code java.lang.Class} of the Object being built 1739 * 1740 * @return A Java {@code Stream<T>}. 1741 */ 1742 public static <T> Stream<T> objArrayToStream 1743 (JsonArray ja, T defaultValue, int FLAGS, Class<T> returnClass) 1744 { 1745 return objArrayToStreamINTERNAL 1746 (ja, RECORD.getObjectStreamRec(defaultValue, FLAGS, returnClass)); 1747 } 1748 1749 private static <T> Stream<T> objArrayToStreamINTERNAL 1750 (JsonArray ja, RECORD<T, Stream<T>> rec) 1751 { 1752 int SIZE = ja.size(); 1753 JsonValue jv = null; 1754 1755 rec.c.run(); // Construct a new Stream-Builder 1756 rec.ja = ja; 1757 1758 for (int i=0; i < SIZE; i++) 1759 1760 switch ((jv = ja.get(i)).getValueType()) 1761 { 1762 // javax.json.JsonValue.ValueType.NULL 1763 case NULL: 1764 rec.handlerNull.run(); 1765 break; 1766 1767 // javax.json.JsonValue.ValueType.OBJECT 1768 case OBJECT: 1769 rec.a.accept(ReadJSON.getObject(((JsonObject) jv), rec.CLASS)); 1770 break; 1771 1772 // javax.json.JsonValue.ValueType.NUMBER, STRING, TRUE, FALSE, ARRAY 1773 default: 1774 if (rec.handlerWrongType != null) rec.handlerWrongType.run(); 1775 else throw new JsonTypeArrException(ja, i, TRUE, jv, rec.CLASS); 1776 } 1777 1778 // Run Stream.Builder.build() 1779 return rec.b.get(); 1780 } 1781 1782 /** 1783 * Parses Multi-Dimensional JSON Array's into Multi-Dimensional Java Array's. 1784 * 1785 * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE> 1786 * <EMBED CLASS='external-html' DATA-FILE-ID=READ_ARR_JDIMN> 1787 * 1788 * @see Json 1789 * @see JsonArray 1790 */ 1791 @Torello.JavaDoc.StaticFunctional 1792 @Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI") 1793 public static class DimN 1794 { 1795 private DimN() { } 1796 1797 /** 1798 * Check user input, and throws exceptions if the array-class has not been properly 1799 * chosen. 1800 * @param retArrClass This must be a primitive-array class, possibly of multiple dimensions 1801 * 1802 * @param rootClass The expected "root class". For {@code int[][].class}, the root class 1803 * would be {@code int.class}. 1804 * 1805 * @return Parameter {@code retArrClass} is the return value of this checker method 1806 * 1807 * @throws IllegalArgumentExcetion If parameter {@code retArrClass}: 1808 * <BR /><BR /><OL CLASS=JDOL> 1809 * <LI>If calling {@code retArrClass.isArray()} returns {@code FALSE}</LI> 1810 * <LI>If the root-array type is not the appropriate type for the method that was called 1811 * </LI> 1812 * </OL> 1813 */ 1814 private static <T> Class<T> CHECK_ARRAY_CLASS(Class<T> retArrClass, Class<?> rootClass) 1815 { 1816 if (! retArrClass.isArray()) throw new IllegalArgumentException( 1817 "The class you have passed to parameter 'retArrClass' " + 1818 "[" + retArrClass.getSimpleName() + "], is not an array" 1819 ); 1820 1821 Class<?> componentClass = retArrClass.getComponentType(); 1822 1823 while (componentClass.isArray()) componentClass = componentClass.getComponentType(); 1824 1825 if (! rootClass.equals(componentClass)) throw new IllegalArgumentException( 1826 "The class you have passed to parameter 'retArrClass' " + 1827 "[" + retArrClass.getSimpleName() + "], is not a(n) " + 1828 rootClass.getSimpleName() + "-array." 1829 ); 1830 1831 return retArrClass; 1832 } 1833 1834 private static Class<?> GET_ARRAY_BASE_COMPONENT_CLASS_AND_CHECK 1835 (Class<?> retArrClass, Object defaultValue) 1836 { 1837 if (! retArrClass.isArray()) throw new IllegalArgumentException( 1838 "The class you have passed to parameter 'retArrClass' " + 1839 "[" + retArrClass.getSimpleName() + "], is not an array" 1840 ); 1841 1842 Class<?> componentClass = retArrClass.getComponentType(); 1843 1844 while (componentClass.isArray()) componentClass = componentClass.getComponentType(); 1845 1846 if ( (defaultValue != null) 1847 && componentClass.isAssignableFrom(defaultValue.getClass()) 1848 ) 1849 1850 throw new IllegalArgumentException( 1851 "The User Provided Default Value of type: "+ 1852 "[" + defaultValue.getClass().getName() + "], cannot be assigned to the " + 1853 "Component-Type of the Array: " + 1854 "[" + componentClass.getName() + "]" 1855 ); 1856 1857 return componentClass; 1858 } 1859 1860 1861 1862 // **************************************************************************************** 1863 // **************************************************************************************** 1864 // Primitive Multi-Dimensional Array Methods 1865 // **************************************************************************************** 1866 // **************************************************************************************** 1867 1868 1869 /** 1870 * Convenience Method. 1871 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 1872 * <BR />Passes: {@code int} Configuration-RECORD 1873 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 1874 * <BR /> 1875 * <BR />See link above for more {@link JFlag} explanations. 1876 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code int}-array. 1877 * <BR />(See last <B>"return-type"</B> parameter in example below) 1878 * 1879 * <DIV CLASS=LOC>{@code 1880 * int[][] arr = ReadArrJSON.DimN.intArr(jsonArray, -1, 0, null, int[][].class); 1881 * }</DIV> 1882 */ 1883 public static <T> T intArr( 1884 JsonArray ja, int defaultValue, int FLAGS, 1885 ToIntFunction<String> optionalUserParser, Class<T> retArrClass 1886 ) 1887 { 1888 return jsonArrToJavaArr( 1889 ja, 1890 RECORD.getIntStreamRec 1891 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser), 1892 CHECK_ARRAY_CLASS(retArrClass, int.class) 1893 ); 1894 } 1895 1896 /** 1897 * Convenience Method. 1898 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 1899 * <BR />Passes: {@code long} Configuration-RECORD 1900 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 1901 * <BR /> 1902 * <BR />See link above for more {@link JFlag} explanations. 1903 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code long}-array. 1904 * <BR />(See last <B>"return-type"</B> parameter in example below) 1905 * 1906 * <DIV CLASS=LOC>{@code 1907 * long[][] arr = ReadArrJSON.DimN.longArr(jsonArray, -1, 0, null, long[][].class); 1908 * }</DIV> 1909 */ 1910 public static <T> T longArr( 1911 JsonArray ja, long defaultValue, int FLAGS, 1912 ToLongFunction<String> optionalUserParser, Class<T> retArrClass 1913 ) 1914 { 1915 return jsonArrToJavaArr( 1916 ja, 1917 RECORD.getLongStreamRec 1918 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser), 1919 CHECK_ARRAY_CLASS(retArrClass, long.class) 1920 ); 1921 } 1922 1923 /** 1924 * Convenience Method. 1925 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 1926 * <BR />Passes: {@code double} Configuration-RECORD 1927 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 1928 * <BR /> 1929 * <BR />See link above for more {@link JFlag} explanations. 1930 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code double}-array. 1931 * <BR />(See last <B>"return-type"</B> parameter in example below) 1932 * 1933 * <DIV CLASS=LOC>{@code 1934 * double[][] arr = ReadArrJSON.DimN.doubleArr(jsonArray, -1, 0, null, double[][].class); 1935 * }</DIV> 1936 */ 1937 public static <T> T doubleArr( 1938 JsonArray ja, double defaultValue, int FLAGS, 1939 ToDoubleFunction<String> optionalUserParser, Class<T> retArrClass 1940 ) 1941 { 1942 return jsonArrToJavaArr( 1943 ja, 1944 RECORD.getDoubleStreamRec 1945 (defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, optionalUserParser), 1946 CHECK_ARRAY_CLASS(retArrClass, double.class) 1947 ); 1948 } 1949 1950 /** 1951 * Convenience Method. 1952 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 1953 * <BR />Passes: {@code short} Configuration-RECORD 1954 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 1955 * <BR /> 1956 * <BR />See link above for more {@link JFlag} explanations. 1957 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code short}-array. 1958 * <BR />(See last <B>"return-type"</B> parameter in example below) 1959 * 1960 * <DIV CLASS=LOC>{@code 1961 * short[][] arr = ReadArrJSON.DimN.shortArr(jsonArray, -1, 0, null, short[][].class); 1962 * }</DIV> 1963 */ 1964 public static <T> T shortArr( 1965 JsonArray ja, short defaultValue, int FLAGS, 1966 ToShortFunction<String> optionalUserParser, Class<T> retArrClass 1967 ) 1968 { 1969 return jsonArrToJavaArr( 1970 ja, 1971 RECORD.getSHORTStreamRec( 1972 defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 1973 (optionalUserParser != null) 1974 ? (String s) -> optionalUserParser.applyAsShort(s) 1975 : null, 1976 true 1977 ), 1978 CHECK_ARRAY_CLASS(retArrClass, short.class) 1979 ); 1980 } 1981 1982 /** 1983 * Convenience Method. 1984 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 1985 * <BR />Passes: {@code byte} Configuration-RECORD 1986 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 1987 * <BR /> 1988 * <BR />See link above for more {@link JFlag} explanations. 1989 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code byte}-array. 1990 * <BR />(See last <B>"return-type"</B> parameter in example below) 1991 * 1992 * <DIV CLASS=LOC>{@code 1993 * byte[][] arr = ReadArrJSON.DimN.byteArr(jsonArray, -1, 0, null, byte[][].class); 1994 * }</DIV> 1995 */ 1996 public static <T> T byteArr( 1997 JsonArray ja, byte defaultValue, int FLAGS, 1998 ToByteFunction<String> optionalUserParser, Class<T> retArrClass 1999 ) 2000 { 2001 return jsonArrToJavaArr( 2002 ja, 2003 RECORD.getBYTEStreamRec( 2004 defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 2005 (optionalUserParser != null) 2006 ? (String s) -> optionalUserParser.applyAsByte(s) 2007 : null, 2008 true 2009 ), 2010 CHECK_ARRAY_CLASS(retArrClass, byte.class) 2011 ); 2012 } 2013 2014 /** 2015 * Convenience Method. 2016 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2017 * <BR />Passes: {@code float} Configuration-RECORD 2018 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 2019 * <BR /> 2020 * <BR />See link above for more {@link JFlag} explanations. 2021 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code float}-array. 2022 * <BR />(See last <B>"return-type"</B> parameter in example below) 2023 * 2024 * <DIV CLASS=LOC>{@code 2025 * float[][] arr = ReadArrJSON.DimN.floatArr(jsonArray, -1, 0, null, float[][].class); 2026 * }</DIV> 2027 */ 2028 public static <T> T floatArr( 2029 JsonArray ja, float defaultValue, int FLAGS, 2030 ToFloatFunction<String> optionalUserParser, Class<T> retArrClass 2031 ) 2032 { 2033 return jsonArrToJavaArr( 2034 ja, 2035 RECORD.getFLOATStreamRec( 2036 defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 2037 (optionalUserParser != null) 2038 ? (String s) -> optionalUserParser.applyAsFloat(s) 2039 : null, 2040 true 2041 ), 2042 CHECK_ARRAY_CLASS(retArrClass, float.class) 2043 ); 2044 } 2045 2046 /** 2047 * Convenience Method. 2048 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2049 * <BR />Passes: {@code boolean} Configuration-RECORD 2050 * <BR />Removes: Any {@code FLAGS} that would produce a null array-entry 2051 * <BR /> 2052 * <BR />See link above for more {@link JFlag} explanations. 2053 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code boolean}-array. 2054 * <BR />(See last <B>"return-type"</B> parameter in example below) 2055 * 2056 * <DIV CLASS=LOC>{@code 2057 * boolean[][] arr = ReadArrJSON.DimN.booleanArr 2058 * (jsonArray, -1, 0, null, boolean[][].class); 2059 * }</DIV> 2060 */ 2061 public static <T> T booleanArr( 2062 JsonArray ja, boolean defaultValue, int FLAGS, 2063 Predicate<String> optionalUserParser, Class<T> retArrClass 2064 ) 2065 { 2066 return jsonArrToJavaArr( 2067 ja, 2068 RECORD.getBOOLEANStreamRec( 2069 defaultValue, FLAGS & NOT_ALLOWED_RET_NULL_MASKS, 2070 (optionalUserParser != null) 2071 ? (String s) -> optionalUserParser.test(s) 2072 : null, 2073 true 2074 ), 2075 CHECK_ARRAY_CLASS(retArrClass, boolean.class) 2076 ); 2077 } 2078 2079 2080 // **************************************************************************************** 2081 // **************************************************************************************** 2082 // Boxed-Primitive Multi-Dimensional Array Methods 2083 // **************************************************************************************** 2084 // **************************************************************************************** 2085 2086 2087 /** 2088 * Convenience Method. 2089 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2090 * <BR />Passes: {@code Integer} Configuration-RECORD 2091 * <BR />See link above for more {@link JFlag} explanations. 2092 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Integer}-array. 2093 * <BR />(See last <B>"return-type"</B> parameter in example below) 2094 * 2095 * <DIV CLASS=LOC>{@code 2096 * Integer[][] arr = ReadArrJSON.DimN.arrINTEGER(jsonArray, -1, 0, null, Integer[][].class); 2097 * }</DIV> 2098 */ 2099 public static <T> T arrINTEGER( 2100 JsonArray ja, int defaultValue, int FLAGS, 2101 Function<String, Integer> optionalUserParser, Class<T> retArrClass 2102 ) 2103 { 2104 return jsonArrToJavaArr( 2105 ja, 2106 RECORD.getINTEGERStreamRec(defaultValue, FLAGS, optionalUserParser), 2107 CHECK_ARRAY_CLASS(retArrClass, Integer.class) 2108 ); 2109 } 2110 2111 /** 2112 * Convenience Method. 2113 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2114 * <BR />Passes: {@code Long} Configuration-RECORD 2115 * <BR />See link above for more {@link JFlag} explanations. 2116 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Long}-array. 2117 * <BR />(See last <B>"return-type"</B> parameter in example below) 2118 * 2119 * <DIV CLASS=LOC>{@code 2120 * Long[][] arr = ReadArrJSON.DimN.arrLONG(jsonArray, -1, 0, null, Long[][].class); 2121 * }</DIV> 2122 */ 2123 public static <T> T arrLONG( 2124 JsonArray ja, long defaultValue, int FLAGS, 2125 Function<String, Long> optionalUserParser, Class<T> retArrClass 2126 ) 2127 { 2128 return jsonArrToJavaArr( 2129 ja, 2130 RECORD.getLONGStreamRec(defaultValue, FLAGS, optionalUserParser), 2131 CHECK_ARRAY_CLASS(retArrClass, Long.class) 2132 ); 2133 } 2134 2135 /** 2136 * Convenience Method. 2137 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2138 * <BR />Passes: {@code Double} Configuration-RECORD 2139 * <BR />See link above for more {@link JFlag} explanations. 2140 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Double}-array. 2141 * <BR />(See last <B>"return-type"</B> parameter in example below) 2142 * 2143 * <DIV CLASS=LOC>{@code 2144 * Double[][] arr = ReadArrJSON.DimN.arrDOUBLE(jsonArray, -1, 0, null, Double[][].class); 2145 * }</DIV> 2146 */ 2147 public static <T> T arrDOUBLE( 2148 JsonArray ja, double defaultValue, int FLAGS, 2149 Function<String, Double> optionalUserParser, Class<T> retArrClass 2150 ) 2151 { 2152 return jsonArrToJavaArr( 2153 ja, 2154 RECORD.getDOUBLEStreamRec(defaultValue, FLAGS, optionalUserParser), 2155 CHECK_ARRAY_CLASS(retArrClass, Double.class) 2156 ); 2157 } 2158 2159 /** 2160 * Convenience Method. 2161 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2162 * <BR />Passes: {@code Short} Configuration-RECORD 2163 * <BR />See link above for more {@link JFlag} explanations. 2164 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Short}-array. 2165 * <BR />(See last <B>"return-type"</B> parameter in example below) 2166 * 2167 * <DIV CLASS=LOC>{@code 2168 * Short[][] arr = ReadArrJSON.DimN.arrSHORT(jsonArray, -1, 0, null, Short[][].class); 2169 * }</DIV> 2170 */ 2171 public static <T> T arrSHORT( 2172 JsonArray ja, short defaultValue, int FLAGS, 2173 Function<String, Short> optionalUserParser, Class<T> retArrClass 2174 ) 2175 { 2176 return jsonArrToJavaArr( 2177 ja, 2178 RECORD.getSHORTStreamRec(defaultValue, FLAGS, optionalUserParser, true), 2179 CHECK_ARRAY_CLASS(retArrClass, Short.class) 2180 ); 2181 } 2182 2183 /** 2184 * Convenience Method. 2185 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2186 * <BR />Passes: {@code Byte} Configuration-RECORD 2187 * <BR />See link above for more {@link JFlag} explanations. 2188 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Byte}-array. 2189 * <BR />(See last <B>"return-type"</B> parameter in example below) 2190 * 2191 * <DIV CLASS=LOC>{@code 2192 * Byte[][] arr = ReadArrJSON.DimN.arrBYTE(jsonArray, -1, 0, null, Byte[][].class); 2193 * }</DIV> 2194 */ 2195 public static <T> T arrBYTE( 2196 JsonArray ja, byte defaultValue, int FLAGS, 2197 Function<String, Byte> optionalUserParser, Class<T> retArrClass 2198 ) 2199 { 2200 return jsonArrToJavaArr( 2201 ja, 2202 RECORD.getBYTEStreamRec(defaultValue, FLAGS, optionalUserParser, true), 2203 CHECK_ARRAY_CLASS(retArrClass, Byte.class) 2204 ); 2205 } 2206 2207 /** 2208 * Convenience Method. 2209 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2210 * <BR />Passes: {@code Float} Configuration-RECORD 2211 * <BR />See link above for more {@link JFlag} explanations. 2212 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Float}-array. 2213 * <BR />(See last <B>"return-type"</B> parameter in example below) 2214 * 2215 * <DIV CLASS=LOC>{@code 2216 * Float[][] arr = ReadArrJSON.DimN.arrFLOAT(jsonArray, -1, 0, null, Float[][].class); 2217 * }</DIV> 2218 */ 2219 public static <T> T arrFLOAT( 2220 JsonArray ja, float defaultValue, int FLAGS, 2221 Function<String, Float> optionalUserParser, Class<T> retArrClass 2222 ) 2223 { 2224 return jsonArrToJavaArr( 2225 ja, 2226 RECORD.getFLOATStreamRec(defaultValue, FLAGS, optionalUserParser, true), 2227 CHECK_ARRAY_CLASS(retArrClass, Float.class) 2228 ); 2229 } 2230 2231 /** 2232 * Convenience Method. 2233 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2234 * <BR />Passes: {@code Boolean} Configuration-RECORD 2235 * <BR />See link above for more {@link JFlag} explanations. 2236 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Boolean}-array. 2237 * <BR />(See last <B>"return-type"</B> parameter in example below) 2238 * 2239 * <DIV CLASS=LOC>{@code 2240 * Boolean[][] arr = ReadArrJSON.DimN.arrBOOLEAN 2241 * (jsonArray, false, 0, null, Boolean[][].class); 2242 * }</DIV> 2243 */ 2244 public static <T> T arrBOOLEAN( 2245 JsonArray ja, boolean defaultValue, int FLAGS, 2246 Function<String, Boolean> optionalUserParser, Class<T> retArrClass 2247 ) 2248 { 2249 return jsonArrToJavaArr( 2250 ja, 2251 RECORD.getBOOLEANStreamRec(defaultValue, FLAGS, optionalUserParser, true), 2252 CHECK_ARRAY_CLASS(retArrClass, Boolean.class) 2253 ); 2254 } 2255 2256 /** 2257 * Convenience Method. 2258 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2259 * <BR />Passes: {@code Number} Configuration-RECORD 2260 * <BR />See link above for more {@link JFlag} explanations. 2261 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Number}-array. 2262 * <BR />(See last <B>"return-type"</B> parameter in example below) 2263 * 2264 * <DIV CLASS=LOC>{@code 2265 * Number[][] arr = ReadArrJSON.DimN.arrNumber(jsonArray, -1, 0, null, Number[][].class); 2266 * }</DIV> 2267 */ 2268 public static <T> T arrNumber( 2269 JsonArray ja, Number defaultValue, int FLAGS, 2270 Function<String, Number> optionalUserParser, Class<T> retArrClass 2271 ) 2272 { 2273 return jsonArrToJavaArr( 2274 ja, 2275 RECORD.getNumberStreamRec(defaultValue, FLAGS, optionalUserParser), 2276 CHECK_ARRAY_CLASS(retArrClass, Number.class) 2277 ); 2278 } 2279 2280 2281 // **************************************************************************************** 2282 // **************************************************************************************** 2283 // Non-Primitive Multi-Dimensional Array Methods 2284 // **************************************************************************************** 2285 // **************************************************************************************** 2286 2287 2288 /** 2289 * Convenience Method. 2290 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2291 * <BR />Passes: {@code String} Configuration-RECORD 2292 * <BR />See link above for more {@link JFlag} explanations. 2293 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code String}-array. 2294 * <BR />(See last <B>"return-type"</B> parameter in example below) 2295 * 2296 * <DIV CLASS=LOC>{@code 2297 * String[][] arr = ReadArrJSON.DimN.strArr(jsonArray, null, 0, String[][].class); 2298 * }</DIV> 2299 */ 2300 public static <T> T strArr 2301 (JsonArray ja, String defaultValue, int FLAGS, Class<T> retArrClass) 2302 { 2303 return jsonArrToJavaArr( 2304 ja, 2305 RECORD.getStringStreamRec(defaultValue, FLAGS), 2306 CHECK_ARRAY_CLASS(retArrClass, String.class) 2307 ); 2308 } 2309 2310 /** 2311 * Convenience Method. 2312 * <BR />Invokes: {@link #jsonArrToJavaArr(JsonArray, ReadArrJSON.RECORD, Class)} 2313 * <BR />Passes: {@code Object} Configuration-RECORD 2314 * <BR />See link above for more {@link JFlag} explanations. 2315 * <BR /><B>NOTE:</B> {@code retArrClass} must be a multi-dimensinal {@code Object}-array. 2316 * <BR />(See last <B>"return-type"</B> parameter in example below) 2317 * 2318 * <DIV CLASS=LOC>{@code 2319 * MyClass[][] arr = ReadArrJSON.DimN.strArr(jsonArray, null, 0, MyClass[][].class); 2320 * }</DIV> 2321 */ 2322 @SuppressWarnings({"rawtypes", "unchecked"}) 2323 public static <T, U> T objArr 2324 (JsonArray ja, Object defaultValue, int FLAGS, Class<T> retArrClass) 2325 { 2326 Class baseClass = // (Class<U>) 2327 GET_ARRAY_BASE_COMPONENT_CLASS_AND_CHECK(retArrClass, defaultValue); 2328 2329 return jsonArrToJavaArr 2330 (ja, RECORD.getObjectStreamRec(baseClass.cast(defaultValue), FLAGS, baseClass), retArrClass); 2331 } 2332 2333 2334 // **************************************************************************************** 2335 // **************************************************************************************** 2336 // The General Purpose Transformer Method 2337 // **************************************************************************************** 2338 // **************************************************************************************** 2339 2340 2341 /** 2342 * The array processor for this class. Handles all multi-dimensional array processing 2343 * requests. 2344 * 2345 * @param <T> The array type being returned. This {@code java.lang.Class} must be an 2346 * array-class. 2347 * 2348 * @param ja Any {@link JsonArray} 2349 * @param rec The Configuration-Record 2350 * @param retArrClass The class of the return array type. 2351 * 2352 * @return An array of type {@code T} 2353 * 2354 * @throws JsonNullPrimitiveArrException <EMBED CLASS='external-html' 2355 * DATA-FILE-ID=RARR_BS_JNPAEX> 2356 * @throws JsonArithmeticArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JAAEX> 2357 * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JSPAEX> 2358 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=RARR_BS_JTAEX> 2359 */ 2360 @SuppressWarnings("unchecked") 2361 protected static <T> T jsonArrToJavaArr 2362 (JsonArray ja, RECORD<?, ?> rec, Class<T> retArrClass) 2363 { 2364 // If this is requesting a one-dimensional array, get it using the 1D-Generator, 2365 // and simply return that array. This requires a cast because there is no way to prove 2366 // to the Java-Compiler that <T> is equal to any return-value at all. 2367 // 2368 // Remember that this is only guaranteed (it works!) because the helper methods are all 2369 // protected or private, and it has been guaranteed through rigorous testing, and 2370 // preventing the user from playing with it! 2371 2372 if (StringParse.countCharacters(retArrClass.getSimpleName(), '[') == 1) 2373 return (T) rec.array1DGenerator.apply(ja); 2374 2375 // Otherwise, this is not a single-dimension (1D) array. Instead, the JsonArray needs 2376 // to be iterated, and this method called, recursively, on each of the sub-arrays. 2377 // 2378 // NOTE: 'compClass' will also be an array, but with one fewer dimensions 2379 2380 Class<?> compClass = retArrClass.getComponentType(); 2381 int SIZE = ja.size(); 2382 T retArr = (T) Array.newInstance(compClass, SIZE); 2383 JsonValue jv = null; 2384 2385 for (int i=0; i < SIZE; i++) 2386 2387 switch ((jv = ja.get(i)).getValueType()) 2388 { 2389 // javax.json.JsonValue.ValueType.NULL 2390 case NULL: Array.set(retArr, i, null); break; 2391 2392 // javax.json.JsonValue.ValueType.ARRAY (JsonArray) 2393 case ARRAY: 2394 Array.set 2395 (retArr, i, jsonArrToJavaArr((JsonArray) jv, rec, compClass)); 2396 break; 2397 2398 // javax.json.JsonValue.ValueType.TRUE, FALSE, NUMBER, STRING, OBJECT 2399 default: 2400 if (rec.IN_NSAT) Array.set(retArr, i, null); 2401 else if (rec.S_NSAT) continue; 2402 else throw new JsonTypeArrException(ja, i, ARRAY, jv, retArrClass); 2403 } 2404 2405 return retArr; 2406 } 2407 } 2408}