001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.util; 019 020 021import java.net.URI; 022import java.net.URISyntaxException; 023import java.text.ParseException; 024import java.util.Arrays; 025import java.util.List; 026 027import net.minidev.json.JSONArray; 028import net.minidev.json.JSONObject; 029import net.minidev.json.parser.JSONParser; 030 031 032/** 033 * JSON object helper methods for parsing and typed retrieval of member values. 034 * 035 * @author Vladimir Dzhuvinov 036 * @version 2018-11-06 037 */ 038public class JSONObjectUtils { 039 040 041 /** 042 * Parses a JSON object. 043 * 044 * <p>Specific JSON to Java entity mapping (as per JSON Smart): 045 * 046 * <ul> 047 * <li>JSON true|false map to {@code java.lang.Boolean}. 048 * <li>JSON numbers map to {@code java.lang.Number}. 049 * <ul> 050 * <li>JSON integer numbers map to {@code long}. 051 * <li>JSON fraction numbers map to {@code double}. 052 * </ul> 053 * <li>JSON strings map to {@code java.lang.String}. 054 * <li>JSON arrays map to {@code net.minidev.json.JSONArray}. 055 * <li>JSON objects map to {@code net.minidev.json.JSONObject}. 056 * </ul> 057 * 058 * @param s The JSON object string to parse. Must not be {@code null}. 059 * 060 * @return The JSON object. 061 * 062 * @throws ParseException If the string cannot be parsed to a valid JSON 063 * object. 064 */ 065 public static JSONObject parse(final String s) 066 throws ParseException { 067 068 Object o; 069 070 try { 071 o = new JSONParser(JSONParser.USE_HI_PRECISION_FLOAT | JSONParser.ACCEPT_TAILLING_SPACE).parse(s); 072 073 } catch (net.minidev.json.parser.ParseException e) { 074 075 throw new ParseException("Invalid JSON: " + e.getMessage(), 0); 076 } catch (Exception e) { 077 throw new ParseException("Unexpected exception: " + e.getMessage(), 0); 078 } 079 080 if (o instanceof JSONObject) { 081 return (JSONObject)o; 082 } else { 083 throw new ParseException("JSON entity is not an object", 0); 084 } 085 } 086 087 088 /** 089 * Use {@link #parse(String)} instead. 090 * 091 * @param s The JSON object string to parse. Must not be {@code null}. 092 * 093 * @return The JSON object. 094 * 095 * @throws ParseException If the string cannot be parsed to a valid JSON 096 * object. 097 */ 098 @Deprecated 099 public static JSONObject parseJSONObject(final String s) 100 throws ParseException { 101 102 return parse(s); 103 } 104 105 106 /** 107 * Gets a generic member of a JSON object. 108 * 109 * @param o The JSON object. Must not be {@code null}. 110 * @param key The JSON object member key. Must not be {@code null}. 111 * @param clazz The expected class of the JSON object member value. Must 112 * not be {@code null}. 113 * 114 * @return The JSON object member value, may be {@code null}. 115 * 116 * @throws ParseException If the value is not of the expected type. 117 */ 118 @SuppressWarnings("unchecked") 119 private static <T> T getGeneric(final JSONObject o, final String key, final Class<T> clazz) 120 throws ParseException { 121 122 if (o.get(key) == null) { 123 return null; 124 } 125 126 Object value = o.get(key); 127 128 if (! clazz.isAssignableFrom(value.getClass())) { 129 throw new ParseException("Unexpected type of JSON object member with key \"" + key + "\"", 0); 130 } 131 132 return (T)value; 133 } 134 135 136 /** 137 * Gets a boolean member of a JSON object. 138 * 139 * @param o The JSON object. Must not be {@code null}. 140 * @param key The JSON object member key. Must not be {@code null}. 141 * 142 * @return The JSON object member value. 143 * 144 * @throws ParseException If the member is missing, the value is 145 * {@code null} or not of the expected type. 146 */ 147 public static boolean getBoolean(final JSONObject o, final String key) 148 throws ParseException { 149 150 Boolean value = getGeneric(o, key, Boolean.class); 151 152 if (value == null) { 153 throw new ParseException("JSON object member with key \"" + key + "\" is missing or null", 0); 154 } 155 156 return value; 157 } 158 159 160 /** 161 * Gets an number member of a JSON object as {@code int}. 162 * 163 * @param o The JSON object. Must not be {@code null}. 164 * @param key The JSON object member key. Must not be {@code null}. 165 * 166 * @return The JSON object member value. 167 * 168 * @throws ParseException If the member is missing, the value is 169 * {@code null} or not of the expected type. 170 */ 171 public static int getInt(final JSONObject o, final String key) 172 throws ParseException { 173 174 Number value = getGeneric(o, key, Number.class); 175 176 if (value == null) { 177 throw new ParseException("JSON object member with key \"" + key + "\" is missing or null", 0); 178 } 179 180 return value.intValue(); 181 } 182 183 184 /** 185 * Gets a number member of a JSON object as {@code long}. 186 * 187 * @param o The JSON object. Must not be {@code null}. 188 * @param key The JSON object member key. Must not be {@code null}. 189 * 190 * @return The JSON object member value. 191 * 192 * @throws ParseException If the member is missing, the value is 193 * {@code null} or not of the expected type. 194 */ 195 public static long getLong(final JSONObject o, final String key) 196 throws ParseException { 197 198 Number value = getGeneric(o, key, Number.class); 199 200 if (value == null) { 201 throw new ParseException("JSON object member with key \"" + key + "\" is missing or null", 0); 202 } 203 204 return value.longValue(); 205 } 206 207 208 /** 209 * Gets a number member of a JSON object {@code float}. 210 * 211 * @param o The JSON object. Must not be {@code null}. 212 * @param key The JSON object member key. Must not be {@code null}. 213 * 214 * @return The JSON object member value, may be {@code null}. 215 * 216 * @throws ParseException If the member is missing, the value is 217 * {@code null} or not of the expected type. 218 */ 219 public static float getFloat(final JSONObject o, final String key) 220 throws ParseException { 221 222 Number value = getGeneric(o, key, Number.class); 223 224 if (value == null) { 225 throw new ParseException("JSON object member with key \"" + key + "\" is missing or null", 0); 226 } 227 228 return value.floatValue(); 229 } 230 231 232 /** 233 * Gets a number member of a JSON object as {@code double}. 234 * 235 * @param o The JSON object. Must not be {@code null}. 236 * @param key The JSON object member key. Must not be {@code null}. 237 * 238 * @return The JSON object member value, may be {@code null}. 239 * 240 * @throws ParseException If the member is missing, the value is 241 * {@code null} or not of the expected type. 242 */ 243 public static double getDouble(final JSONObject o, final String key) 244 throws ParseException { 245 246 Number value = getGeneric(o, key, Number.class); 247 248 if (value == null) { 249 throw new ParseException("JSON object member with key \"" + key + "\" is missing or null", 0); 250 } 251 252 return value.doubleValue(); 253 } 254 255 256 /** 257 * Gets a string member of a JSON object. 258 * 259 * @param o The JSON object. Must not be {@code null}. 260 * @param key The JSON object member key. Must not be {@code null}. 261 * 262 * @return The JSON object member value, may be {@code null}. 263 * 264 * @throws ParseException If the value is not of the expected type. 265 */ 266 public static String getString(final JSONObject o, final String key) 267 throws ParseException { 268 269 return getGeneric(o, key, String.class); 270 } 271 272 273 /** 274 * Gets a string member of a JSON object as {@code java.net.URI}. 275 * 276 * @param o The JSON object. Must not be {@code null}. 277 * @param key The JSON object member key. Must not be {@code null}. 278 * 279 * @return The JSON object member value, may be {@code null}. 280 * 281 * @throws ParseException If the value is not of the expected type. 282 */ 283 public static URI getURI(final JSONObject o, final String key) 284 throws ParseException { 285 286 String value = getString(o, key); 287 288 if (value == null) { 289 return null; 290 } 291 292 try { 293 return new URI(value); 294 295 } catch (URISyntaxException e) { 296 297 throw new ParseException(e.getMessage(), 0); 298 } 299 } 300 301 302 /** 303 * Gets a JSON array member of a JSON object. 304 * 305 * @param o The JSON object. Must not be {@code null}. 306 * @param key The JSON object member key. Must not be {@code null}. 307 * 308 * @return The JSON object member value, may be {@code null}. 309 * 310 * @throws ParseException If the value is not of the expected type. 311 */ 312 public static JSONArray getJSONArray(final JSONObject o, final String key) 313 throws ParseException { 314 315 return getGeneric(o, key, JSONArray.class); 316 } 317 318 319 /** 320 * Gets a string array member of a JSON object. 321 * 322 * @param o The JSON object. Must not be {@code null}. 323 * @param key The JSON object member key. Must not be {@code null}. 324 * 325 * @return The JSON object member value, may be {@code null}. 326 * 327 * @throws ParseException If the value is not of the expected type. 328 */ 329 public static String[] getStringArray(final JSONObject o, final String key) 330 throws ParseException { 331 332 JSONArray jsonArray = getJSONArray(o, key); 333 334 if (jsonArray == null) { 335 return null; 336 } 337 338 try { 339 return jsonArray.toArray(new String[0]); 340 341 } catch (ArrayStoreException e) { 342 343 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings", 0); 344 } 345 } 346 347 348 /** 349 * Gets a string list member of a JSON object 350 * 351 * @param o The JSON object. Must not be {@code null}. 352 * @param key The JSON object member key. Must not be {@code null}. 353 * 354 * @return The JSON object member value, may be {@code null}. 355 * 356 * @throws ParseException If the value is not of the expected type. 357 */ 358 public static List<String> getStringList(final JSONObject o, final String key) throws ParseException { 359 360 String[] array = getStringArray(o, key); 361 362 if (array == null) { 363 return null; 364 } 365 366 return Arrays.asList(array); 367 } 368 369 370 /** 371 * Gets a JSON object member of a JSON object. 372 * 373 * @param o The JSON object. Must not be {@code null}. 374 * @param key The JSON object member key. Must not be {@code null}. 375 * 376 * @return The JSON object member value, may be {@code null}. 377 * 378 * @throws ParseException If the value is not of the expected type. 379 */ 380 public static JSONObject getJSONObject(final JSONObject o, final String key) 381 throws ParseException { 382 383 return getGeneric(o, key, JSONObject.class); 384 } 385 386 387 /** 388 * Prevents public instantiation. 389 */ 390 private JSONObjectUtils() { } 391} 392