001package Torello.JSON; 002 003import Torello.JavaDoc.Annotations.IntoHTMLTable; 004import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.BlueDither; 005import static Torello.JavaDoc.Annotations.IntoHTMLTable.Background.GreenDither; 006 007import java.math.BigDecimal; 008import java.util.function.Function; 009 010import javax.json.JsonObject; 011import javax.json.JsonArray; 012import javax.json.JsonNumber; 013import javax.json.JsonValue; 014 015import static javax.json.JsonValue.ValueType.TRUE; 016import static javax.json.JsonValue.ValueType.NUMBER; 017import static javax.json.JsonValue.ValueType.NULL; 018 019/** 020 * Builds on the J2EE Standard Release JSON Parsing Tools by providing additional 021 * help with converting JSON Data into <B STYLE='color: red'>Java Primitive-Types</B> 022 * 023 * <EMBED CLASS='external-html' DATA-FILE-ID=ALL_CLASSES_NOTE> 024 * <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_JSON> 025 * <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_PTABLE> 026 * <EMBED CLASS='external-html' DATA-CH=char DATA-FILE-ID=JAVA_LANG_CHAR> 027 * 028 * @see JsonObject 029 * @see JsonArray 030 */ 031@Torello.JavaDoc.Annotations.StaticFunctional 032public class ReadPrimJSON 033{ 034 // This is a static class. Has no program state. 035 private ReadPrimJSON() { } 036 037 038 // ******************************************************************************************** 039 // ******************************************************************************************** 040 // Read from a JsonArray 041 // ******************************************************************************************** 042 // ******************************************************************************************** 043 044 045 /** 046 * <EMBED CLASS='external-html' DATA-TYPE=int DATA-FILE-ID=READ_PRIM_JA> 047 * @see #GET(JsonArray, int, Class) 048 * @see JsonNumber#intValueExact() 049 */ 050 @IntoHTMLTable( 051 title="Extract a JsonNumber from a JsonArray, and Transform it to a Java 'int' Primitive", 052 background=BlueDither 053 ) 054 public static int getInt(final JsonArray ja, final int index) 055 { 056 final JsonNumber jn = GET(ja, index, int.class); 057 058 try 059 { return jn.intValueExact(); } 060 061 catch (ArithmeticException ae) 062 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, int.class); } 063 } 064 065 /** 066 * <EMBED CLASS='external-html' DATA-TYPE=long DATA-FILE-ID=READ_PRIM_JA> 067 * @see #GET(JsonArray, int, Class) 068 * @see JsonNumber#longValueExact() 069 */ 070 @IntoHTMLTable( 071 title="Extract a JsonNumber from a JsonArray, and Transform it to a Java 'long' Primitive", 072 background=GreenDither 073 ) 074 public static long getLong(final JsonArray ja, final int index) 075 { 076 final JsonNumber jn = GET(ja, index, long.class); 077 078 try 079 { return jn.longValueExact(); } 080 081 catch (ArithmeticException ae) 082 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, long.class); } 083 } 084 085 /** 086 * <EMBED CLASS='external-html' DATA-TYPE=short DATA-FILE-ID=READ_PRIM_JA> 087 * @see #GET(JsonArray, int, Class) 088 * @see JsonNumber#longValueExact() 089 * @see RJInternal#SHORT_FROM_LONG(long) 090 */ 091 @IntoHTMLTable( 092 title= 093 "Extract a JsonNumber from a JsonArray, and Transform it to a Java 'short' Primitive", 094 background=BlueDither 095 ) 096 public static short getShort(final JsonArray ja, final int index) 097 { 098 final JsonNumber jn = GET(ja, index, short.class); 099 100 try 101 { return RJInternal.SHORT_FROM_LONG(jn.longValueExact()); } 102 103 catch (ArithmeticException ae) 104 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, short.class); } 105 } 106 107 /** 108 * <EMBED CLASS='external-html' DATA-TYPE=byte DATA-FILE-ID=READ_PRIM_JA> 109 * @see #GET(JsonArray, int, Class) 110 * @see JsonNumber#longValueExact() 111 * @see RJInternal#BYTE_FROM_LONG(long) 112 */ 113 @IntoHTMLTable( 114 title="Extract a JsonNumber from a JsonArray, and Transform it to a Java 'byte' Primitive", 115 background=GreenDither 116 ) 117 public static byte getByte(final JsonArray ja, final int index) 118 { 119 final JsonNumber jn = GET(ja, index, byte.class); 120 121 try 122 { return RJInternal.BYTE_FROM_LONG(jn.longValueExact()); } 123 124 catch (ArithmeticException ae) 125 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, byte.class); } 126 } 127 128 /** 129 * <EMBED CLASS='external-html' DATA-TYPE=double DATA-FILE-ID=READ_PRIM_JA> 130 * @see #GET(JsonArray, int, Class) 131 * @see RJInternal#DOUBLE_WITH_CHECK(BigDecimal) 132 */ 133 @IntoHTMLTable( 134 title= 135 "Extract a JsonNumber from a JsonArray, and Transform it to a Java 'double' " + 136 "Primitive", 137 background=BlueDither 138 ) 139 public static double getDouble(final JsonArray ja, final int index) 140 { 141 final JsonNumber jn = GET(ja, index, double.class); 142 143 try 144 { return RJInternal.DOUBLE_WITH_CHECK(jn.bigDecimalValue()); } 145 146 catch (ArithmeticException ae) 147 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, double.class); } 148 } 149 150 /** 151 * <EMBED CLASS='external-html' DATA-TYPE=float DATA-FILE-ID=READ_PRIM_JA> 152 * @see #GET(JsonArray, int, Class) 153 * @see RJInternal#FLOAT_WITH_CHECK(BigDecimal) 154 */ 155 @IntoHTMLTable( 156 title= 157 "Extract a JsonNumber from a JsonArray, and Transform it to a Java 'float' Primitive", 158 background=GreenDither 159 ) 160 public static float getFloat(final JsonArray ja, final int index) 161 { 162 final JsonNumber jn = GET(ja, index, float.class); 163 164 try 165 { return RJInternal.FLOAT_WITH_CHECK(jn.bigDecimalValue()); } 166 167 catch (ArithmeticException ae) 168 { throw new JsonArithmeticArrException(ae, ja, index, NUMBER, jn, float.class); } 169 } 170 171 /** <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_JA_BOOL> */ 172 @IntoHTMLTable( 173 title= 174 "Extract Json-True or False from a JsonArray, and Transform it to a Java " + 175 "'boolean' Primitive", 176 background=BlueDither 177 ) 178 public static boolean getBoolean(final JsonArray ja, final int index) 179 { 180 final JsonValue jv = ja.get(index); 181 182 switch (jv.getValueType()) // throws IOB if necessary 183 { 184 case NULL: throw new JsonNullPrimitiveArrException 185 (ja, index, TRUE, boolean.class); 186 187 case TRUE: return true; 188 case FALSE: return false; 189 190 default: throw new JsonTypeArrException 191 (ja, index, TRUE, jv, boolean.class); 192 } 193 } 194 195 196 // ******************************************************************************************** 197 // ******************************************************************************************** 198 // Internal GET 199 // ******************************************************************************************** 200 // ******************************************************************************************** 201 202 203 /** 204 * This is an internal helper method for retrieving an element from a {@link JsonArray}, 205 * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>. 206 * 207 * @param ja Any instance of {@link JsonArray} 208 * @param index Any index into the array which holds a {@link JsonNumber} 209 * @param primitiveClass <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_PCLASS> 210 * 211 * @return The extracted {@link JsonNumber}. 212 * 213 * @throws JsonNullPrimitiveArrException If the array element at {@code 'index'} contains 214 * <B STYLE='color: red'>Json-Null</B> 215 * @throws JsonTypeArrException If the array element at {@code 'index'} doesn't contain 216 * {@link JsonNumber} 217 * @throws JsonArithmeticArrException If there are any arithmetic problems during conversion 218 * @throws IndexOutOfBoundsException If {@code 'index'} is out of the bounds of {@code 'ja'} 219 * 220 * @see #getInt(JsonArray, int) 221 * @see #getLong(JsonArray, int) 222 * @see #getShort(JsonArray, int) 223 * @see #getByte(JsonArray, int) 224 * @see #getDouble(JsonArray, int) 225 * @see #getFloat(JsonArray, int) 226 */ 227 protected static <T> JsonNumber GET( 228 final JsonArray ja, 229 final int index, 230 final Class<T> primitiveClass 231 ) 232 { 233 // This will throw an IndexOutOfBoundsException if the index is out of bounds. 234 final JsonValue jv = ja.get(index); 235 236 switch (jv.getValueType()) 237 { 238 case NULL: throw new JsonNullPrimitiveArrException 239 (ja, index, NUMBER, primitiveClass); 240 241 case NUMBER: return (JsonNumber) jv; 242 243 default: throw new JsonTypeArrException 244 (ja, index, NUMBER, jv, primitiveClass); 245 } 246 } 247 248 249 // ******************************************************************************************** 250 // ******************************************************************************************** 251 // Read from a JsonObject 252 // ******************************************************************************************** 253 // ******************************************************************************************** 254 255 256 /** 257 * <EMBED CLASS='external-html' DATA-TYPE=int DATA-FILE-ID=READ_PRIM_JO> 258 * @see #GET(JsonObject, String, Class) 259 * @see JsonNumber#intValueExact() 260 */ 261 @IntoHTMLTable( 262 title="Extract a JsonNumber from a JsonObject, and Transform it to a Java 'int' Primitive", 263 background=GreenDither 264 ) 265 public static int getInt(final JsonObject jo, final String propertyName) 266 { 267 final JsonNumber jn = GET(jo, propertyName, int.class); 268 269 try 270 { return jn.intValueExact(); } 271 272 catch (ArithmeticException ae) 273 { throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, int.class); } 274 } 275 276 /** 277 * <EMBED CLASS='external-html' DATA-TYPE=long DATA-FILE-ID=READ_PRIM_JO> 278 * @see #GET(JsonObject, String, Class) 279 * @see JsonNumber#longValueExact() 280 */ 281 @IntoHTMLTable( 282 title= 283 "Extract a JsonNumber from a JsonObject, and Transform it to a Java 'long' Primitive", 284 background=BlueDither 285 ) 286 public static long getLong(final JsonObject jo, final String propertyName) 287 { 288 final JsonNumber jn = GET(jo, propertyName, long.class); 289 290 try 291 { return jn.longValueExact(); } 292 293 catch (ArithmeticException ae) 294 { throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, long.class); } 295 } 296 297 /** 298 * <EMBED CLASS='external-html' DATA-TYPE=short DATA-FILE-ID=READ_PRIM_JO> 299 * @see #GET(JsonObject, String, Class) 300 * @see JsonNumber#longValueExact() 301 * @see RJInternal#SHORT_FROM_LONG(long) 302 */ 303 @IntoHTMLTable( 304 title= 305 "Extract a JsonNumber from a JsonObject, and Transform it to a Java 'short' Primitive", 306 background=GreenDither 307 ) 308 public static short getShort(final JsonObject jo, final String propertyName) 309 { 310 final JsonNumber jn = GET(jo, propertyName, short.class); 311 312 try 313 { return RJInternal.SHORT_FROM_LONG(jn.longValueExact()); } 314 315 catch (ArithmeticException ae) 316 { 317 throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, short.class); 318 } 319 } 320 321 /** 322 * <EMBED CLASS='external-html' DATA-TYPE=byte DATA-FILE-ID=READ_PRIM_JO> 323 * @see #GET(JsonObject, String, Class) 324 * @see JsonNumber#longValueExact() 325 * @see RJInternal#BYTE_FROM_LONG(long) 326 */ 327 @IntoHTMLTable( 328 title= 329 "Extract a JsonNumber from a JsonObject, and Transform it to a Java 'byte' Primitive", 330 background=BlueDither 331 ) 332 public static byte getByte(final JsonObject jo, final String propertyName) 333 { 334 final JsonNumber jn = GET(jo, propertyName, byte.class); 335 336 try 337 { return RJInternal.BYTE_FROM_LONG(jn.longValueExact()); } 338 339 catch (ArithmeticException ae) 340 { throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, byte.class); } 341 } 342 343 /** 344 * <EMBED CLASS='external-html' DATA-TYPE=double DATA-FILE-ID=READ_PRIM_JO> 345 * @see #GET(JsonObject, String, Class) 346 * @see RJInternal#DOUBLE_WITH_CHECK(BigDecimal) 347 */ 348 @IntoHTMLTable( 349 title= 350 "Extract a JsonNumber from a JsonObject, and Transform it to a Java 'double' " + 351 "Primitive", 352 background=GreenDither 353 ) 354 public static double getDouble(final JsonObject jo, final String propertyName) 355 { 356 final JsonNumber jn = GET(jo, propertyName, double.class); 357 358 try 359 { return RJInternal.DOUBLE_WITH_CHECK(jn.bigDecimalValue()); } 360 361 catch (ArithmeticException ae) 362 { 363 throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, double.class); 364 } 365 } 366 367 /** 368 * <EMBED CLASS='external-html' DATA-TYPE=float DATA-FILE-ID=READ_PRIM_JO> 369 * @see #GET(JsonObject, String, Class) 370 * @see RJInternal#FLOAT_WITH_CHECK(BigDecimal) 371 */ 372 @IntoHTMLTable( 373 title= 374 "Extract a JsonNumber from a JsonObject, and Transform it to a Java 'float' Primitive", 375 background=BlueDither 376 ) 377 public static float getFloat(final JsonObject jo, final String propertyName) 378 { 379 final JsonNumber jn = GET(jo, propertyName, float.class); 380 381 try 382 { return RJInternal.FLOAT_WITH_CHECK(jn.bigDecimalValue()); } 383 384 catch (ArithmeticException ae) 385 { 386 throw new JsonArithmeticObjException(ae, jo, propertyName, NUMBER, jn, float.class); 387 } 388 } 389 390 /** <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_JO_BOOL> */ 391 @IntoHTMLTable( 392 title= 393 "Extract Json-True or False from a JsonObject, and Transform it to a Java 'long' " + 394 "Primitive", 395 background=GreenDither 396 ) 397 public static boolean getBoolean(final JsonObject jo, final String propertyName) 398 { 399 if (! jo.containsKey(propertyName)) throw new JsonPropMissingException 400 (jo, propertyName, TRUE, boolean.class); 401 402 final JsonValue jv = jo.get(propertyName); 403 404 switch (jv.getValueType()) 405 { 406 case NULL: throw new JsonNullPrimitiveObjException 407 (jo, propertyName, TRUE, boolean.class); 408 409 case TRUE: return true; 410 case FALSE: return false; 411 412 default: throw new JsonTypeObjException 413 (jo, propertyName, TRUE, jv, boolean.class); 414 } 415 } 416 417 418 // ******************************************************************************************** 419 // ******************************************************************************************** 420 // The Internal Methods 421 // ******************************************************************************************** 422 // ******************************************************************************************** 423 424 425 /** 426 * This is an internal helper method for retrieving a property from a {@link JsonObject}, 427 * and converting it to one of the standard <B STYLE='color: red;'>Java Types</B>. 428 * 429 * @param jo Any instance of {@link JsonObject} 430 * @param propertyName Any property name contained by {@code 'jo'} 431 * @param primitiveClass <EMBED CLASS='external-html' DATA-FILE-ID=READ_PRIM_PCLASS> 432 * 433 * @return The extracted {@link JsonNumber}. 434 * 435 * @throws JsonNullPrimitiveObjException If the specified property contains 436 * <B STYLE='color: red'>Json-Null</B> 437 * @throws JsonPropMissingException If the property is missing, and {@code 'isOptional'} 438 * is {@code FALSE}. 439 * @throws JsonTypeObjException If the user specified property doesn't contain a 440 * {@link JsonNumber} 441 * @throws JsonArithmeticObjException If there any arithmetic problems during the conversion 442 * 443 * @see #getInt(JsonObject, String) 444 * @see #getLong(JsonObject, String) 445 * @see #getShort(JsonObject, String) 446 * @see #getByte(JsonObject, String) 447 * @see #getDouble(JsonObject, String) 448 * @see #getFloat(JsonObject, String) 449 */ 450 protected static <T> JsonNumber GET( 451 final JsonObject jo, 452 final String propertyName, 453 final Class<T> primitiveClass 454 ) 455 { 456 // Here, a 'get' request was made for a property that isn't actually listed among the 457 // properties in the provided JsonObject. Since this internal 'GET' is used by methods 458 // that are trying to return a Java Primitive (like 'int' or 'float'), then an exception 459 // has to be thrown. The option of returning 'null' isn't possible here! 460 461 if (! jo.containsKey(propertyName)) throw new JsonPropMissingException 462 (jo, propertyName, NUMBER, primitiveClass); 463 464 final JsonValue jv = jo.get(propertyName); 465 466 switch (jv.getValueType()) 467 { 468 case NULL: throw new JsonNullPrimitiveObjException 469 (jo, propertyName, NUMBER, primitiveClass); 470 471 case NUMBER: return (JsonNumber) jv; 472 473 // The JsonObject property does not contain a JsonNumber. 474 default: throw new JsonTypeObjException 475 (jo, propertyName, NUMBER, jv, primitiveClass); 476 } 477 } 478 479}