001package Torello.Java.JSON; 002 003import javax.json.*; 004import java.lang.reflect.*; 005import java.math.*; 006 007import java.util.function.Function; 008 009import static javax.json.JsonValue.ValueType.*; 010import static Torello.Java.JSON.JFlag.*; 011import static Torello.Java.JSON.RJInternal.*; 012 013/** 014 * Builds on the J2EE Standard Release JSON Parsing Tools by providing additional 015 * help with converting JSON Data into the Best-Fit 016 * <B STYLE='color: red'><CODE>java.lang.Number</CODE></B> 017 * 018 * <EMBED CLASS='external-html' DATA-FILE-ID=GLASS_FISH_NOTE> 019 * 020 * @see Json 021 * @see JsonObject 022 * @see JsonArray 023 */ 024@Torello.JavaDoc.StaticFunctional 025@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JSON_JDHBI") 026public class ReadNumberJSON 027{ 028 // This is a static class. Has no program state. 029 private ReadNumberJSON() { } 030 031 032 // ******************************************************************************************** 033 // ******************************************************************************************** 034 // Number from JsonArray 035 // ******************************************************************************************** 036 // ******************************************************************************************** 037 038 039 /** 040 * Retrieve a {@link JsonArray} element, and transform it to a {@code java.lang.Number}. 041 * <EMBED CLASS=defs DATA-JTYPE=JsonNumber DATA-TYPE='java.lang.Number'> 042 * <EMBED CLASS='external-html' DATA-FILE-ID=JR_NUMBER> 043 * 044 * @param ja Any instance of {@link JsonArray} 045 * @param index <EMBED CLASS='external-html' DATA-FILE-ID=JR_INDEX_JA> 046 * @param throwOnNull <EMBED CLASS='external-html' DATA-FILE-ID=JR_TON_JA> 047 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JR_RET_TON_JA> 048 * 049 * @throws IndexOutOfBoundsException If {@code 'index'} is out of the bounds of {@code 'ja'} 050 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTAEX> 051 * @throws JsonNullArrException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNAEX> 052 * 053 * @see JsonValue#getValueType() 054 * @see RJInternal#convertToNumber(JsonNumber) 055 */ 056 public static Number get(JsonArray ja, int index, boolean throwOnNull) 057 { 058 // This will throw an IndexOutOfBoundsException if the index is out of bounds. 059 JsonValue jv = ja.get(index); 060 061 switch (jv.getValueType()) 062 { 063 case NULL: 064 065 // This is simple-stuff (not rocket-science). "Type Mapping" Code has to worry 066 // about what the meaning of "null" should be. 067 068 if (throwOnNull) throw new JsonNullArrException(ja, index, NUMBER, Number.class); 069 else return null; 070 071 case NUMBER: return convertToNumber((JsonNumber) jv); 072 073 // The JsonValue at the specified array-index does not contain a JsonString. 074 default: throw new JsonTypeArrException(ja, index, NUMBER, jv, Number.class); 075 } 076 } 077 078 /** 079 * Retrieve a {@link JsonArray} element, and transform it to a {@code java.lang.Number}. 080 * <EMBED CLASS=defs DATA-TYPE='java.lang.Number' DATA-JTYPE=JsonNumber> 081 * <EMBED CLASS='external-html' DATA-FILE-ID=JR_NUMBER> 082 * 083 * @param ja Any instance of {@link JsonArray} 084 * @param index The array index containing the element to retrieve. 085 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 086 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRF_DEFV> 087 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRF_RET_JA> 088 * 089 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_IOOBEX> 090 * @throws JsonNullArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNAEX> 091 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTAEX> 092 * 093 * @see RJInternal#GET(JsonArray, int, int, Number, Class, Function, Function) 094 * @see RJInternal#convertToNumber(JsonNumber) 095 */ 096 public static Number get(JsonArray ja, int index, int FLAGS, Number defaultValue) 097 { return GET(ja, index, FLAGS, defaultValue, Number.class, RJInternal::convertToNumber, null); } 098 099 /** 100 * Retrieve a {@link JsonArray} element containing a {@link JsonString}, and transform it to a 101 * {@code java.lang.Number}, with either a user-provided parser, or the standard java parser 102 * 103 * <EMBED CLASS=defs DATA-TYPE='java.lang.Number' DATA-JTYPE=JsonString 104 * DATA-PARSER='new BigDecimal'> 105 * 106 * <BR /><BR />If {@code 'parser'} is passed null, the default parser is used, which is just 107 * the {@code java.math.BigDecimal} constructor which accepts a {@code String}. What is done 108 * with the parsed {@code BigDecimal} instance is explained below. 109 * 110 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=JR_NUM_PARSE> 111 * 112 * @param ja Any instance of {@link JsonArray} 113 * @param index The array index containing the {@link JsonString} element to retrieve. 114 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 115 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRF_DEFV> 116 * @param optionalParser <EMBED CLASS='external-html' DATA-FILE-ID=JRF_PARSER> 117 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRF_PARSERET_JA> 118 * 119 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_IOOBEX> 120 * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JSPAEX> 121 * @throws JsonNullArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNAEX> 122 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTAEX> 123 * 124 * @see RJInternal#PARSE(JsonObject, String, int, Number, Class, Function, Function, Function) 125 * @see RJInternal#convertToNumber(String) 126 */ 127 public static Number parse( 128 JsonArray ja, int index, int FLAGS, Number defaultValue, 129 Function<String, Number> optionalParser 130 ) 131 { 132 return PARSE( 133 ja, index, FLAGS, defaultValue, Number.class, optionalParser, 134 RJInternal::convertToNumber, null /* Not Needed, convertToNumber won't throw */ 135 ); 136 } 137 138 139 // ******************************************************************************************** 140 // ******************************************************************************************** 141 // Number from JsonObject 142 // ******************************************************************************************** 143 // ******************************************************************************************** 144 145 146 /** 147 * Extract a {@link JsonObject} property, and transform it to a {@code java.lang.Number}. 148 * <EMBED CLASS=defs DATA-TYPE='java.lang.Number' DATA-JTYPE=JsonNumber> 149 * <EMBED CLASS='external-html' DATA-FILE-ID=JR_NUMBER> 150 * 151 * @param jo Any instance of {@link JsonObject}. 152 * @param propertyName <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO> 153 * @param isOptional <EMBED CLASS='external-html' DATA-FILE-ID=JR_ISOPT_JO> 154 * @param throwOnNull <EMBED CLASS='external-html' DATA-FILE-ID=JR_TON_JO> 155 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JR_RET_TON_JO> 156 * 157 * @throws JsonPropMissingException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JPMEX> 158 * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JTOEX> 159 * @throws JsonNullObjException <EMBED CLASS='external-html' DATA-FILE-ID=JR_JNOEX> 160 * 161 * @see JsonValue#getValueType() 162 * @see RJInternal#convertToNumber(JsonNumber) 163 */ 164 public static Number get 165 (JsonObject jo, String propertyName, boolean isOptional, boolean throwOnNull) 166 { 167 if (! jo.containsKey(propertyName)) 168 { 169 if (isOptional) return null; 170 else throw new JsonPropMissingException(jo, propertyName, NUMBER, Number.class); 171 } 172 173 JsonValue jv = jo.get(propertyName); 174 175 switch (jv.getValueType()) 176 { 177 case NULL: 178 179 // This is simple-stuff (not rocket-science). "Type Mapping" Code has to worry 180 // about what the meaning of "null" should be. 181 182 if (throwOnNull) throw new JsonNullObjException 183 (jo, propertyName, NUMBER, Number.class); 184 185 else return null; 186 187 case NUMBER: return convertToNumber((JsonNumber) jv); 188 189 // The JsonObject propertydoes not contain a JsonNumber. 190 default: throw new JsonTypeObjException 191 (jo, propertyName, NUMBER, jv, Number.class); 192 } 193 } 194 195 /** 196 * Retrieve a {@link JsonObject} property, and transform it to a {@code java.lang.Number}. 197 * <EMBED CLASS=defs DATA-TYPE='java.lang.Number' DATA-JTYPE=JsonNumber> 198 * <EMBED CLASS='external-html' DATA-FILE-ID=JR_NUMBER> 199 * 200 * @param jo Any instance of {@link JsonObject} 201 * @param propertyName <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO> 202 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 203 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRF_DEFV> 204 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRF_RET_JO> 205 * 206 * @throws JsonPropMissingException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JPMEX> 207 * @throws JsonNullObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNOEX> 208 * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTOEX> 209 * 210 * @see RJInternal#GET(JsonObject, String, int, Number, Class, Function, Function) 211 * @see RJInternal#convertToNumber(JsonNumber) 212 */ 213 public static Number get 214 (JsonObject jo, String propertyName, int FLAGS, Number defaultValue) 215 { 216 return GET 217 (jo, propertyName, FLAGS, defaultValue, Number.class, RJInternal::convertToNumber, null); 218 } 219 220 /** 221 * Retrieve a {@link JsonObject} property containing a {@link JsonString}, and transform it to 222 * a {@code java.lang.Number}, with either a user-provided parser, or the standard java 223 * parser 224 * 225 * <EMBED CLASS=defs DATA-TYPE='java.lang.Number' DATA-JTYPE=JsonString 226 * DATA-PARSER='new BigDecimal'> 227 * 228 * <BR /><BR />If {@code 'parser'} is passed null, the default parser is used, which is just 229 * the {@code java.math.BigDecimal} constructor which accepts a {@code String}. What is done 230 * with the parsed {@code BigDecimal} instance is explained below. 231 * 232 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=JR_NUM_PARSE> 233 * 234 * @param jo Any instance of {@link JsonObject} 235 * @param propertyName <EMBED CLASS='external-html' DATA-FILE-ID=JR_PN_JO> 236 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 237 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRF_DEFV> 238 * @param optionalParser <EMBED CLASS='external-html' DATA-FILE-ID=JRF_PARSER> 239 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRF_PARSERET_JO> 240 * 241 * @throws JsonPropMissingException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JPMEX> 242 * @throws JsonStrParseObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JSPOEX> 243 * @throws JsonNullObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JNOEX> 244 * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JTOEX> 245 * 246 * @see RJInternal#PARSE(JsonObject, String, int, Number, Class, Function, Function, Function) 247 * @see RJInternal#convertToNumber(String) 248 */ 249 public static Number parse( 250 JsonObject jo, String propertyName, int FLAGS, Number defaultValue, 251 Function<String, Number> optionalParser 252 ) 253 { 254 return PARSE( 255 jo, propertyName, FLAGS, defaultValue, Number.class, optionalParser, 256 RJInternal::convertToNumber, null /* Not Needed, convertToNumber won't throw */ 257 ); 258 } 259 260 261 // ******************************************************************************************** 262 // ******************************************************************************************** 263 // Number from JsonString Parse **OR** from JsonNumber 264 // ******************************************************************************************** 265 // ******************************************************************************************** 266 267 268 /** 269 * <EMBED CLASS=defs DATA-TYPE=Number DATA-PARSER='new BigDecimal'> 270 * <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_DESC_JA> 271 * 272 * @param ja Any {@link JsonArray} 273 * @param i Any index into the {@code JsonArray} 274 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 275 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_DEFVAL> 276 * @param optionalParser <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_PARSER> 277 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_RET_JA> 278 * 279 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_IOOBEX> 280 * @throws JsonStrParseArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JSPAEX> 281 * @throws JsonNullArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JNAEX> 282 * @throws JsonTypeArrException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JTAEX> 283 * 284 * @see #get(JsonArray, int, int, Number) 285 * @see #parse(JsonArray, int, int, Number, Function) 286 */ 287 public static Number get( 288 JsonArray ja, int i, int FLAGS, Number defaultValue, 289 Function<String, Number> optionalParser 290 ) 291 { 292 JsonValue.ValueType t; 293 294 return ((i >= ja.size()) || ((t=ja.get(i).getValueType()) == NUMBER) || (t != STRING)) 295 ? get(ja, i, FLAGS, defaultValue) 296 : parse(ja, i, FLAGS, defaultValue, optionalParser); 297 } 298 299 /** 300 * <EMBED CLASS=defs DATA-TYPE=Number DATA-PARSER='new BigDecimal'> 301 * <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_DESC_JO> 302 * 303 * @param jo Any {@link JsonObject} 304 * @param propertyName Any of the properties defined in the {@code JsonObject} 305 * @param FLAGS Return-value / exception-throw constants defined in {@link JFlag} 306 * @param defaultValue <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_DEFVAL> 307 * @param optionalParser <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_PARSER> 308 * @return <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_RET_JO> 309 * 310 * @throws JsonPropMissingException <EMBED CLASS='external-html' DATA-FILE-ID=JRF_JPMEX> 311 * @throws JsonStrParseObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JSPOEX> 312 * @throws JsonNullObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JNOEX> 313 * @throws JsonTypeObjException <EMBED CLASS='external-html' DATA-FILE-ID=JRXL_JTOEX> 314 * 315 * @see #get(JsonObject, String, int, Number) 316 * @see #parse(JsonObject, String, int, Number, Function) 317 */ 318 public static Number get( 319 JsonObject jo, String propertyName, int FLAGS, Number defaultValue, 320 Function<String, Number> optionalParser 321 ) 322 { 323 JsonValue.ValueType t; 324 325 return ( (! jo.containsKey(propertyName)) 326 || ((t = jo.get(propertyName).getValueType()) == NUMBER) 327 || (t != STRING) 328 ) 329 ? get(jo, propertyName, FLAGS, defaultValue) 330 : parse(jo, propertyName, FLAGS, defaultValue, optionalParser); 331 } 332}