001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 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.oauth2.sdk.util; 019 020 021import java.net.MalformedURLException; 022import java.net.URI; 023import java.net.URISyntaxException; 024import java.net.URL; 025import java.util.Arrays; 026import java.util.HashSet; 027import java.util.List; 028import java.util.Set; 029 030import javax.mail.internet.AddressException; 031import javax.mail.internet.InternetAddress; 032 033import net.minidev.json.JSONArray; 034import net.minidev.json.JSONObject; 035 036import com.nimbusds.oauth2.sdk.ParseException; 037 038 039/** 040 * JSON object helper methods for parsing and typed retrieval of member values. 041 */ 042public class JSONObjectUtils { 043 044 045 /** 046 * Returns {@code true} if the JSON object is defined and contains the 047 * specified key. 048 * 049 * @param jsonObject The JSON object to check. May be {@code null}. 050 * @param key The key to check. Must not be {@code null}. 051 * 052 * @return {@code true} if the JSON object is defined and contains the 053 * specified key, else {@code false}. 054 */ 055 public static boolean containsKey(final JSONObject jsonObject, final String key) { 056 057 return jsonObject != null && jsonObject.containsKey(key); 058 } 059 060 061 /** 062 * Parses a JSON object. 063 * 064 * <p>Specific JSON to Java entity mapping (as per JSON Simple): 065 * 066 * <ul> 067 * <li>JSON numbers mapped to {@code java.lang.Number}. 068 * <li>JSON integer numbers mapped to {@code long}. 069 * <li>JSON fraction numbers mapped to {@code double}. 070 * </ul> 071 * 072 * @param s The JSON object string to parse. Must not be {@code null}. 073 * 074 * @return The JSON object. 075 * 076 * @throws ParseException If the string cannot be parsed to a JSON 077 * object. 078 */ 079 public static JSONObject parse(final String s) 080 throws ParseException { 081 082 Object o = JSONUtils.parseJSON(s); 083 084 if (o instanceof JSONObject) 085 return (JSONObject)o; 086 else 087 throw new ParseException("The JSON entity is not an object"); 088 } 089 090 091 /** 092 * Use {@link #parse(String)} instead. 093 */ 094 @Deprecated 095 public static JSONObject parseJSONObject(final String s) 096 throws ParseException { 097 098 return parse(s); 099 } 100 101 102 /** 103 * Gets a generic member of a JSON object. 104 * 105 * @param o The JSON object. Must not be {@code null}. 106 * @param key The JSON object member key. Must not be {@code null}. 107 * @param clazz The expected class of the JSON object member value. Must 108 * not be {@code null}. 109 * 110 * @return The JSON object member value. 111 * 112 * @throws ParseException If the value is missing, {@code null} or not 113 * of the expected type. 114 */ 115 @SuppressWarnings("unchecked") 116 public static <T> T getGeneric(final JSONObject o, final String key, final Class<T> clazz) 117 throws ParseException { 118 119 if (! o.containsKey(key)) 120 throw new ParseException("Missing JSON object member with key \"" + key + "\""); 121 122 if (o.get(key) == null) 123 throw new ParseException("JSON object member with key \"" + key + "\" has null value"); 124 125 Object value = o.get(key); 126 127 if (! clazz.isAssignableFrom(value.getClass())) 128 throw new ParseException("Unexpected type of JSON object member with key \"" + key + "\""); 129 130 return (T)value; 131 } 132 133 134 /** 135 * Gets a boolean member of a JSON object. 136 * 137 * @param o The JSON object. Must not be {@code null}. 138 * @param key The JSON object member key. Must not be {@code null}. 139 * 140 * @return The member value. 141 * 142 * @throws ParseException If the value is missing, {@code null} or not 143 * of the expected type. 144 */ 145 public static boolean getBoolean(final JSONObject o, final String key) 146 throws ParseException { 147 148 return getGeneric(o, key, Boolean.class); 149 } 150 151 152 /** 153 * Gets an number member of a JSON object as {@code int}. 154 * 155 * @param o The JSON object. Must not be {@code null}. 156 * @param key The JSON object member key. Must not be {@code null}. 157 * 158 * @return The member value. 159 * 160 * @throws ParseException If the value is missing, {@code null} or not 161 * of the expected type. 162 */ 163 public static int getInt(final JSONObject o, final String key) 164 throws ParseException { 165 166 return getGeneric(o, key, Number.class).intValue(); 167 } 168 169 170 /** 171 * Gets a number member of a JSON object as {@code long}. 172 * 173 * @param o The JSON object. Must not be {@code null}. 174 * @param key The JSON object member key. Must not be {@code null}. 175 * 176 * @return The member value. 177 * 178 * @throws ParseException If the value is missing, {@code null} or not 179 * of the expected type. 180 */ 181 public static long getLong(final JSONObject o, final String key) 182 throws ParseException { 183 184 return getGeneric(o, key, Number.class).longValue(); 185 } 186 187 188 /** 189 * Gets a number member of a JSON object {@code float}. 190 * 191 * @param o The JSON object. Must not be {@code null}. 192 * @param key The JSON object member key. Must not be {@code null}. 193 * 194 * @return The member value. 195 * 196 * @throws ParseException If the value is missing, {@code null} or not 197 * of the expected type. 198 */ 199 public static float getFloat(final JSONObject o, final String key) 200 throws ParseException { 201 202 return getGeneric(o, key, Number.class).floatValue(); 203 } 204 205 206 /** 207 * Gets a number member of a JSON object as {@code double}. 208 * 209 * @param o The JSON object. Must not be {@code null}. 210 * @param key The JSON object member key. Must not be {@code null}. 211 * 212 * @return The member value. 213 * 214 * @throws ParseException If the value is missing, {@code null} or not 215 * of the expected type. 216 */ 217 public static double getDouble(final JSONObject o, final String key) 218 throws ParseException { 219 220 return getGeneric(o, key, Number.class).doubleValue(); 221 } 222 223 224 /** 225 * Gets a number member of a JSON object as {@code java.lang.Number}. 226 * 227 * @param o The JSON object. Must not be {@code null}. 228 * @param key The JSON object member key. Must not be {@code null}. 229 * 230 * @return The member value. 231 * 232 * @throws ParseException If the value is missing, {@code null} or not 233 * of the expected type. 234 */ 235 public static Number getNumber(final JSONObject o, final String key) 236 throws ParseException { 237 238 return getGeneric(o, key, Number.class); 239 } 240 241 242 /** 243 * Gets a string member of a JSON object. 244 * 245 * @param o The JSON object. Must not be {@code null}. 246 * @param key The JSON object member key. Must not be {@code null}. 247 * 248 * @return The member value. 249 * 250 * @throws ParseException If the value is missing, {@code null} or not 251 * of the expected type. 252 */ 253 public static String getString(final JSONObject o, final String key) 254 throws ParseException { 255 256 return getGeneric(o, key, String.class); 257 } 258 259 260 /** 261 * Gets a string member of a JSON object as an enumerated object. 262 * 263 * @param o The JSON object. Must not be {@code null}. 264 * @param key The JSON object member key. Must not be 265 * {@code null}. 266 * @param enumClass The enumeration class. Must not be {@code null}. 267 * 268 * @return The member value. 269 * 270 * @throws ParseException If the value is missing, {@code null} or not 271 * of the expected type. 272 */ 273 public static <T extends Enum<T>> T getEnum(final JSONObject o, 274 final String key, 275 final Class<T> enumClass) 276 throws ParseException { 277 278 String value = getString(o, key); 279 280 for (T en: enumClass.getEnumConstants()) { 281 282 if (en.toString().equalsIgnoreCase(value)) 283 return en; 284 } 285 286 throw new ParseException("Unexpected value of JSON object member with key \"" + key + "\""); 287 } 288 289 290 /** 291 * Gets a string member of a JSON object as {@code java.net.URI}. 292 * 293 * @param o The JSON object. Must not be {@code null}. 294 * @param key The JSON object member key. Must not be {@code null}. 295 * 296 * @return The member value. 297 * 298 * @throws ParseException If the value is missing, {@code null} or not 299 * of the expected type. 300 */ 301 public static URI getURI(final JSONObject o, final String key) 302 throws ParseException { 303 304 try { 305 return new URI(getGeneric(o, key, String.class)); 306 307 } catch (URISyntaxException e) { 308 309 throw new ParseException(e.getMessage(), e); 310 } 311 } 312 313 314 /** 315 * Gets a string member of a JSON object as {@code java.net.URL}. 316 * 317 * @param o The JSON object. Must not be {@code null}. 318 * @param key The JSON object member key. Must not be {@code null}. 319 * 320 * @return The member value. 321 * 322 * @throws ParseException If the value is missing, {@code null} or not 323 * of the expected type. 324 */ 325 public static URL getURL(final JSONObject o, final String key) 326 throws ParseException { 327 328 try { 329 return new URL(getGeneric(o, key, String.class)); 330 331 } catch (MalformedURLException e) { 332 333 throw new ParseException(e.getMessage(), e); 334 } 335 } 336 337 338 /** 339 * Gets a string member of a JSON object as 340 * {@code javax.mail.internet.InternetAddress}. 341 * 342 * @param o The JSON object. Must not be {@code null}. 343 * @param key The JSON object member key. Must not be {@code null}. 344 * 345 * @return The member value. 346 * 347 * @throws ParseException If the value is missing, {@code null} or not 348 * of the expected type. 349 */ 350 @Deprecated 351 public static InternetAddress getEmail(final JSONObject o, final String key) 352 throws ParseException { 353 354 try { 355 final boolean strict = true; 356 357 return new InternetAddress(getGeneric(o, key, String.class), strict); 358 359 } catch (AddressException e) { 360 361 throw new ParseException(e.getMessage(), e); 362 } 363 } 364 365 366 /** 367 * Gets a JSON array member of a JSON object. 368 * 369 * @param o The JSON object. Must not be {@code null}. 370 * @param key The JSON object member key. Must not be {@code null}. 371 * 372 * @return The member value. 373 * 374 * @throws ParseException If the value is missing, {@code null} or not 375 * of the expected type. 376 */ 377 public static JSONArray getJSONArray(final JSONObject o, final String key) 378 throws ParseException { 379 380 return getGeneric(o, key, JSONArray.class); 381 } 382 383 384 /** 385 * Gets a list member of a JSON object. 386 * 387 * @param o The JSON object. Must not be {@code null}. 388 * @param key The JSON object member key. Must not be {@code null}. 389 * 390 * @return The member value. 391 * 392 * @throws ParseException If the value is missing, {@code null} or not 393 * of the expected type. 394 */ 395 @SuppressWarnings("unchecked") 396 public static List<Object> getList(final JSONObject o, final String key) 397 throws ParseException { 398 399 return getGeneric(o, key, List.class); 400 } 401 402 403 /** 404 * Gets a string array member of a JSON object. 405 * 406 * @param o The JSON object. Must not be {@code null}. 407 * @param key The JSON object member key. Must not be {@code null}. 408 * 409 * @return The member value. 410 * 411 * @throws ParseException If the value is missing, {@code null} or not 412 * of the expected type. 413 */ 414 public static String[] getStringArray(final JSONObject o, final String key) 415 throws ParseException { 416 417 List<Object> list = getList(o, key); 418 419 try { 420 return list.toArray(new String[0]); 421 422 } catch (ArrayStoreException e) { 423 424 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings"); 425 } 426 } 427 428 429 /** 430 * Gets a string list member of a JSON object. 431 * 432 * @param o The JSON object. Must not be {@code null}. 433 * @param key The JSON object member key. Must not be {@code null}. 434 * 435 * @return The member value. 436 * 437 * @throws ParseException If the value is missing, {@code null} or not 438 * of the expected type. 439 */ 440 public static List<String> getStringList(final JSONObject o, final String key) 441 throws ParseException { 442 443 return Arrays.asList(getStringArray(o, key)); 444 } 445 446 447 /** 448 * Gets a string array member of a JSON object as a string set. 449 * 450 * @param o The JSON object. Must not be {@code null}. 451 * @param key The JSON object member key. Must not be {@code null}. 452 * 453 * @return The member value. 454 * 455 * @throws ParseException If the value is missing, {@code null} or not 456 * of the expected type. 457 */ 458 public static Set<String> getStringSet(final JSONObject o, final String key) 459 throws ParseException { 460 461 List<Object> list = getList(o, key); 462 463 Set<String> set = new HashSet<>(); 464 465 for (Object item: list) { 466 467 try { 468 set.add((String)item); 469 470 } catch (Exception e) { 471 472 throw new ParseException("JSON object member wit key \"" + key + "\" is not an array of strings"); 473 } 474 475 } 476 477 return set; 478 } 479 480 481 /** 482 * Gets a JSON object member of a JSON object. 483 * 484 * @param o The JSON object. Must not be {@code null}. 485 * @param key The JSON object member key. Must not be {@code null}. 486 * 487 * @return The member value. 488 * 489 * @throws ParseException If the value is missing, {@code null} or not 490 * of the expected type. 491 */ 492 public static JSONObject getJSONObject(final JSONObject o, final String key) 493 throws ParseException { 494 495 return getGeneric(o, key, JSONObject.class); 496 } 497 498 499 /** 500 * Prevents instantiation. 501 */ 502 private JSONObjectUtils() { 503 504 // Nothing to do 505 } 506} 507