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.*; 026 027import net.minidev.json.JSONArray; 028import net.minidev.json.JSONObject; 029 030import com.nimbusds.oauth2.sdk.ParseException; 031 032 033/** 034 * JSON object helper methods for parsing and typed retrieval of member values. 035 */ 036public final class JSONObjectUtils { 037 038 039 /** 040 * Returns {@code true} if the JSON object is defined and contains the 041 * specified key. 042 * 043 * @param jsonObject The JSON object to check. May be {@code null}. 044 * @param key The key to check. Must not be {@code null}. 045 * 046 * @return {@code true} if the JSON object is defined and contains the 047 * specified key, else {@code false}. 048 */ 049 public static boolean containsKey(final JSONObject jsonObject, final String key) { 050 051 return jsonObject != null && jsonObject.containsKey(key); 052 } 053 054 055 /** 056 * Parses a JSON object. 057 * 058 * <p>Specific JSON to Java entity mapping (as per JSON Simple): 059 * 060 * <ul> 061 * <li>JSON numbers mapped to {@code java.lang.Number}. 062 * <li>JSON integer numbers mapped to {@code long}. 063 * <li>JSON fraction numbers mapped to {@code double}. 064 * </ul> 065 * 066 * @param s The JSON object string to parse. Must not be {@code null}. 067 * 068 * @return The JSON object. 069 * 070 * @throws ParseException If the string cannot be parsed to a JSON 071 * object. 072 */ 073 public static JSONObject parse(final String s) 074 throws ParseException { 075 076 Object o = JSONUtils.parseJSON(s); 077 078 if (o instanceof JSONObject) 079 return (JSONObject)o; 080 else 081 throw new ParseException("The JSON entity is not an object"); 082 } 083 084 085 /** 086 * Parses a JSON object while keeping the order of JSON object members. 087 * 088 * <p>Specific JSON to Java entity mapping (as per JSON Simple): 089 * 090 * <ul> 091 * <li>JSON numbers mapped to {@code java.lang.Number}. 092 * <li>JSON integer numbers mapped to {@code long}. 093 * <li>JSON fraction numbers mapped to {@code double}. 094 * </ul> 095 * 096 * @param s The JSON object string to parse. Must not be {@code null}. 097 * 098 * @return The JSON object as linked hash map. 099 * 100 * @throws ParseException If the string cannot be parsed to a JSON 101 * object. 102 */ 103 public static LinkedHashMap<String,Object> parseKeepingOrder(final String s) 104 throws ParseException { 105 106 Object o = JSONUtils.parseJSONKeepingOrder(s); 107 108 if (o instanceof LinkedHashMap) 109 return (LinkedHashMap<String,Object>)o; 110 else 111 throw new ParseException("The JSON entity is not an object"); 112 } 113 114 115 /** 116 * Use {@link #parse(String)} instead. 117 * 118 * @param s The JSON object string to parse. Must not be {@code null}. 119 * 120 * @return The JSON object. 121 * 122 * @throws ParseException If the string cannot be parsed to a JSON 123 * object. 124 */ 125 @Deprecated 126 public static JSONObject parseJSONObject(final String s) 127 throws ParseException { 128 129 return parse(s); 130 } 131 132 133 /** 134 * Gets a generic member of a JSON object. 135 * 136 * @param o The JSON object. Must not be {@code null}. 137 * @param key The JSON object member key. Must not be {@code null}. 138 * @param clazz The expected class of the JSON object member value. Must 139 * not be {@code null}. 140 * 141 * @return The JSON object member value. 142 * 143 * @throws ParseException If the value is missing, {@code null} or not 144 * of the expected type. 145 */ 146 public static <T> T getGeneric(final JSONObject o, final String key, final Class<T> clazz) 147 throws ParseException { 148 149 if (! o.containsKey(key)) 150 throw new ParseException("Missing JSON object member with key " + key + ""); 151 152 Object value = o.get(key); 153 154 if (value == null) { 155 throw new ParseException("JSON object member with key " + key + " has null value"); 156 } 157 158 try { 159 return JSONUtils.to(value, clazz); 160 } catch (ParseException e) { 161 throw new ParseException("Unexpected type of JSON object member with key " + key + "", e); 162 } 163 } 164 165 166 /** 167 * Gets a boolean member of a JSON object. 168 * 169 * @param o The JSON object. Must not be {@code null}. 170 * @param key The JSON object member key. Must not be {@code null}. 171 * 172 * @return The member value. 173 * 174 * @throws ParseException If the value is missing, {@code null} or not 175 * of the expected type. 176 */ 177 public static boolean getBoolean(final JSONObject o, final String key) 178 throws ParseException { 179 180 return getGeneric(o, key, Boolean.class); 181 } 182 183 184 /** 185 * Gets a boolean member of a JSON object. 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 * @param def The default value to return if the key is not present or. 190 * the value is {@code null}. May be {@code null}. 191 * 192 * @return The member value. 193 * 194 * @throws ParseException If the value is not of the expected type. 195 */ 196 public static boolean getBoolean(final JSONObject o, final String key, final boolean def) 197 throws ParseException { 198 199 if (o.get(key) != null) { 200 return getBoolean(o, key); 201 } 202 203 return def; 204 } 205 206 207 /** 208 * Gets an number member of a JSON object as {@code int}. 209 * 210 * @param o The JSON object. Must not be {@code null}. 211 * @param key The JSON object member key. Must not be {@code null}. 212 * 213 * @return The member value. 214 * 215 * @throws ParseException If the value is missing, {@code null} or not 216 * of the expected type. 217 */ 218 public static int getInt(final JSONObject o, final String key) 219 throws ParseException { 220 221 return getGeneric(o, key, Number.class).intValue(); 222 } 223 224 225 /** 226 * Gets an number member of a JSON object as {@code int}. 227 * 228 * @param o The JSON object. Must not be {@code null}. 229 * @param key The JSON object member key. Must not be {@code null}. 230 * @param def The default value to return if the key is not present or 231 * the value is {@code null}. 232 * 233 * @return The member value. 234 * 235 * @throws ParseException If the value is not of the expected type. 236 */ 237 public static int getInt(final JSONObject o, final String key, final int def) 238 throws ParseException { 239 240 if (o.get(key) != null) { 241 return getInt(o, key); 242 } 243 244 return def; 245 } 246 247 248 /** 249 * Gets a number member of a JSON object as {@code long}. 250 * 251 * @param o The JSON object. Must not be {@code null}. 252 * @param key The JSON object member key. Must not be {@code null}. 253 * 254 * @return The member value. 255 * 256 * @throws ParseException If the value is missing, {@code null} or not 257 * of the expected type. 258 */ 259 public static long getLong(final JSONObject o, final String key) 260 throws ParseException { 261 262 return getGeneric(o, key, Number.class).longValue(); 263 } 264 265 266 /** 267 * Gets a number member of a JSON object as {@code long}. 268 * 269 * @param o The JSON object. Must not be {@code null}. 270 * @param key The JSON object member key. Must not be {@code null}. 271 * @param def The default value to return if the key is not present or 272 * the value is {@code null}. 273 * 274 * @return The member value. 275 * 276 * @throws ParseException If the value is not of the expected type. 277 */ 278 public static long getLong(final JSONObject o, final String key, final long def) 279 throws ParseException { 280 281 if (o.get(key) != null) { 282 return getLong(o, key); 283 } 284 285 return def; 286 } 287 288 289 /** 290 * Gets a number member of a JSON object {@code float}. 291 * 292 * @param o The JSON object. Must not be {@code null}. 293 * @param key The JSON object member key. Must not be {@code null}. 294 * 295 * @return The member value. 296 * 297 * @throws ParseException If the value is missing, {@code null} or not 298 * of the expected type. 299 */ 300 public static float getFloat(final JSONObject o, final String key) 301 throws ParseException { 302 303 return getGeneric(o, key, Number.class).floatValue(); 304 } 305 306 307 /** 308 * Gets a number member of a JSON object {@code float}. 309 * 310 * @param o The JSON object. Must not be {@code null}. 311 * @param key The JSON object member key. Must not be {@code null}. 312 * @param def The default value to return if the key is not present or 313 * the value is {@code null}. 314 * 315 * @return The member value. 316 * 317 * @throws ParseException If the value is not of the expected type. 318 */ 319 public static float getFloat(final JSONObject o, final String key, final float def) 320 throws ParseException { 321 322 if (o.get(key) != null) { 323 return getFloat(o, key); 324 } 325 326 return def; 327 } 328 329 330 /** 331 * Gets a number member of a JSON object as {@code double}. 332 * 333 * @param o The JSON object. Must not be {@code null}. 334 * @param key The JSON object member key. Must not be {@code null}. 335 * 336 * @return The member value. 337 * 338 * @throws ParseException If the value is missing, {@code null} or not 339 * of the expected type. 340 */ 341 public static double getDouble(final JSONObject o, final String key) 342 throws ParseException { 343 344 return getGeneric(o, key, Number.class).doubleValue(); 345 } 346 347 348 /** 349 * Gets a number member of a JSON object as {@code double}. 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 * @param def The default value to return if the key is not present or 354 * the value is {@code null}. 355 * 356 * @return The member value. 357 * 358 * @throws ParseException If the value is not of the expected type. 359 */ 360 public static double getDouble(final JSONObject o, final String key, final double def) 361 throws ParseException { 362 363 if (o.get(key) != null) { 364 return getDouble(o, key); 365 } 366 367 return def; 368 } 369 370 371 /** 372 * Gets a number member of a JSON object as {@code java.lang.Number}. 373 * 374 * @param o The JSON object. Must not be {@code null}. 375 * @param key The JSON object member key. Must not be {@code null}. 376 * 377 * @return The member value. 378 * 379 * @throws ParseException If the value is missing, {@code null} or not 380 * of the expected type. 381 */ 382 public static Number getNumber(final JSONObject o, final String key) 383 throws ParseException { 384 385 return getGeneric(o, key, Number.class); 386 } 387 388 389 /** 390 * Gets a number member of a JSON object as {@code java.lang.Number}. 391 * 392 * @param o The JSON object. Must not be {@code null}. 393 * @param key The JSON object member key. Must not be {@code null}. 394 * @param def The default value to return if the key is not present or 395 * the value is {@code null}. May be {@code null}. 396 * 397 * @return The member value. 398 * 399 * @throws ParseException If the value is not of the expected type. 400 */ 401 public static Number getNumber(final JSONObject o, final String key, final Number def) 402 throws ParseException { 403 404 if (o.get(key) != null) { 405 return getNumber(o, key); 406 } 407 408 return def; 409 } 410 411 412 /** 413 * Gets a string member of a JSON object. 414 * 415 * @param o The JSON object. Must not be {@code null}. 416 * @param key The JSON object member key. Must not be {@code null}. 417 * 418 * @return The member value. 419 * 420 * @throws ParseException If the value is missing, {@code null} or not 421 * of the expected type. 422 */ 423 public static String getString(final JSONObject o, final String key) 424 throws ParseException { 425 426 return getGeneric(o, key, String.class); 427 } 428 429 430 /** 431 * Gets a string member of a JSON object. 432 * 433 * @param o The JSON object. Must not be {@code null}. 434 * @param key The JSON object member key. Must not be {@code null}. 435 * @param def The default value to return if the key is not present or 436 * the value is {@code null}. May be {@code null}. 437 * 438 * @return The member value. 439 * 440 * @throws ParseException If the value is not of the expected type. 441 */ 442 public static String getString(final JSONObject o, final String key, final String def) 443 throws ParseException { 444 445 if (o.get(key) != null) { 446 return getString(o, key); 447 } 448 449 return def; 450 } 451 452 453 /** 454 * Gets a string member of a JSON object as an enumerated object. 455 * 456 * @param o The JSON object. Must not be {@code null}. 457 * @param key The JSON object member key. Must not be 458 * {@code null}. 459 * @param enumClass The enumeration class. Must not be {@code null}. 460 * 461 * @return The member value. 462 * 463 * @throws ParseException If the value is missing, {@code null} or not 464 * of the expected type. 465 */ 466 public static <T extends Enum<T>> T getEnum(final JSONObject o, 467 final String key, 468 final Class<T> enumClass) 469 throws ParseException { 470 471 String value = getString(o, key); 472 473 for (T en: enumClass.getEnumConstants()) { 474 475 if (en.toString().equalsIgnoreCase(value)) 476 return en; 477 } 478 479 throw new ParseException("Unexpected value of JSON object member with key " + key + ""); 480 } 481 482 483 /** 484 * Gets a string member of a JSON object as an enumerated object. 485 * 486 * @param o The JSON object. Must not be {@code null}. 487 * @param key The JSON object member key. Must not be 488 * {@code null}. 489 * @param enumClass The enumeration class. Must not be {@code null}. 490 * @param def The default value to return if the key is not 491 * present or the value is {@code null}. May be 492 * {@code null}. 493 * 494 * @return The member value. 495 * 496 * @throws ParseException If the value is not of the expected type. 497 */ 498 public static <T extends Enum<T>> T getEnum(final JSONObject o, 499 final String key, 500 final Class<T> enumClass, 501 final T def) 502 throws ParseException { 503 504 if (o.get(key) != null) { 505 return getEnum(o, key, enumClass); 506 } 507 508 return def; 509 } 510 511 512 /** 513 * Gets a string member of a JSON object as {@code java.net.URI}. 514 * 515 * @param o The JSON object. Must not be {@code null}. 516 * @param key The JSON object member key. Must not be {@code null}. 517 * 518 * @return The member value. 519 * 520 * @throws ParseException If the value is missing, {@code null} or not 521 * of the expected type. 522 */ 523 public static URI getURI(final JSONObject o, final String key) 524 throws ParseException { 525 526 try { 527 return new URI(getGeneric(o, key, String.class)); 528 529 } catch (URISyntaxException e) { 530 531 throw new ParseException(e.getMessage(), e); 532 } 533 } 534 535 536 /** 537 * Gets a string member of a JSON object as {@code java.net.URI}. 538 * 539 * @param o The JSON object. Must not be {@code null}. 540 * @param key The JSON object member key. Must not be {@code null}. 541 * @param def The default value to return if the key is not present or 542 * the value is {@code null}. May be {@code null}. 543 * 544 * @return The member value. 545 * 546 * @throws ParseException If the value is not of the expected type. 547 */ 548 public static URI getURI(final JSONObject o, final String key, final URI def) 549 throws ParseException { 550 551 if (o.get(key) != null) { 552 return getURI(o, key); 553 } 554 555 return def; 556 } 557 558 559 /** 560 * Gets a string member of a JSON object as {@code java.net.URL}. 561 * 562 * @param o The JSON object. Must not be {@code null}. 563 * @param key The JSON object member key. Must not be {@code null}. 564 * 565 * @return The member value. 566 * 567 * @throws ParseException If the value is missing, {@code null} or not 568 * of the expected type. 569 */ 570 public static URL getURL(final JSONObject o, final String key) 571 throws ParseException { 572 573 try { 574 return new URL(getGeneric(o, key, String.class)); 575 576 } catch (MalformedURLException e) { 577 578 throw new ParseException(e.getMessage(), e); 579 } 580 } 581 582 583 /** 584 * Gets a JSON array member of a JSON object. 585 * 586 * @param o The JSON object. Must not be {@code null}. 587 * @param key The JSON object member key. Must not be {@code null}. 588 * 589 * @return The member value. 590 * 591 * @throws ParseException If the value is missing, {@code null} or not 592 * of the expected type. 593 */ 594 public static JSONArray getJSONArray(final JSONObject o, final String key) 595 throws ParseException { 596 597 return getGeneric(o, key, JSONArray.class); 598 } 599 600 601 /** 602 * Gets a JSON array member of a JSON object. 603 * 604 * @param o The JSON object. Must not be {@code null}. 605 * @param key The JSON object member key. Must not be {@code null}. 606 * @param def The default value to return if the key is not present or 607 * the value is {@code null}. May be {@code null}. 608 * 609 * @return The member value. 610 * 611 * @throws ParseException If the value is not of the expected type. 612 */ 613 public static JSONArray getJSONArray(final JSONObject o, final String key, final JSONArray def) 614 throws ParseException { 615 616 if (o.get(key) != null) { 617 return getJSONArray(o, key); 618 } 619 620 return def; 621 } 622 623 624 /** 625 * Gets a list member of a JSON object. 626 * 627 * @param o The JSON object. Must not be {@code null}. 628 * @param key The JSON object member key. Must not be {@code null}. 629 * 630 * @return The member value. 631 * 632 * @throws ParseException If the value is missing, {@code null} or not 633 * of the expected type. 634 */ 635 @SuppressWarnings("unchecked") 636 public static List<Object> getList(final JSONObject o, final String key) 637 throws ParseException { 638 639 return getGeneric(o, key, List.class); 640 } 641 642 643 /** 644 * Gets a list member of a JSON object. 645 * 646 * @param o The JSON object. Must not be {@code null}. 647 * @param key The JSON object member key. Must not be {@code null}. 648 * @param def The default value to return if the key is not present or 649 * the value is {@code null}. May be {@code null}. 650 * 651 * @return The member value. 652 * 653 * @throws ParseException If the value is not of the expected type. 654 */ 655 public static List<Object> getList(final JSONObject o, final String key, final List<Object> def) 656 throws ParseException { 657 658 if (o.get(key) != null) { 659 return getList(o, key); 660 } 661 662 return def; 663 } 664 665 666 /** 667 * Gets a string array member of a JSON object. 668 * 669 * @param o The JSON object. Must not be {@code null}. 670 * @param key The JSON object member key. Must not be {@code null}. 671 * 672 * @return The member value. 673 * 674 * @throws ParseException If the value is missing, {@code null} or not 675 * of the expected type. 676 */ 677 public static String[] getStringArray(final JSONObject o, final String key) 678 throws ParseException { 679 680 List<Object> list = getList(o, key); 681 682 try { 683 return list.toArray(new String[0]); 684 685 } catch (ArrayStoreException e) { 686 687 throw new ParseException("JSON object member with key " + key + " is not an array of strings"); 688 } 689 } 690 691 692 /** 693 * Gets a string array member of a JSON object. 694 * 695 * @param o The JSON object. Must not be {@code null}. 696 * @param key The JSON object member key. Must not be {@code null}. 697 * @param def The default value to return if the key is not present or 698 * the value is {@code null}. May be {@code null}. 699 * 700 * @return The member value. 701 * 702 * @throws ParseException If the value is not of the expected type. 703 */ 704 public static String[] getStringArray(final JSONObject o, final String key, final String[] def) 705 throws ParseException { 706 707 if (o.get(key) != null) { 708 return getStringArray(o, key); 709 } 710 711 return def; 712 } 713 714 715 /** 716 * Gets a string list member of a JSON object. 717 * 718 * @param o The JSON object. Must not be {@code null}. 719 * @param key The JSON object member key. Must not be {@code null}. 720 * 721 * @return The member value. 722 * 723 * @throws ParseException If the value is missing, {@code null} or not 724 * of the expected type. 725 */ 726 public static List<String> getStringList(final JSONObject o, final String key) 727 throws ParseException { 728 729 return Arrays.asList(getStringArray(o, key)); 730 } 731 732 733 /** 734 * Gets a string list member of a JSON object. 735 * 736 * @param o The JSON object. Must not be {@code null}. 737 * @param key The JSON object member key. Must not be {@code null}. 738 * @param def The default value to return if the key is not present or 739 * the value is {@code null}. May be {@code null}. 740 * 741 * @return The member value. 742 * 743 * @throws ParseException If the value is not of the expected type. 744 */ 745 public static List<String> getStringList(final JSONObject o, final String key, final List<String> def) 746 throws ParseException { 747 748 if (o.get(key) != null) { 749 return getStringList(o, key); 750 } 751 752 return def; 753 } 754 755 756 /** 757 * Gets a string array member of a JSON object as a string set. 758 * 759 * @param o The JSON object. Must not be {@code null}. 760 * @param key The JSON object member key. Must not be {@code null}. 761 * 762 * @return The member value. 763 * 764 * @throws ParseException If the value is missing, {@code null} or not 765 * of the expected type. 766 */ 767 public static Set<String> getStringSet(final JSONObject o, final String key) 768 throws ParseException { 769 770 List<Object> list = getList(o, key); 771 772 Set<String> set = new HashSet<>(); 773 774 for (Object item: list) { 775 776 try { 777 set.add((String)item); 778 779 } catch (Exception e) { 780 781 throw new ParseException("JSON object member with key " + key + " is not an array of strings"); 782 } 783 784 } 785 786 return set; 787 } 788 789 790 /** 791 * Gets a string array member of a JSON object as a string set. 792 * 793 * @param o The JSON object. Must not be {@code null}. 794 * @param key The JSON object member key. Must not be {@code null}. 795 * @param def The default value to return if the key is not present or 796 * the value is {@code null}. May be {@code null}. 797 * 798 * @return The member value. 799 * 800 * @throws ParseException If the value is not of the expected type. 801 */ 802 public static Set<String> getStringSet(final JSONObject o, final String key, final Set<String> def) 803 throws ParseException { 804 805 if (o.get(key) != null) { 806 return getStringSet(o, key); 807 } 808 809 return def; 810 } 811 812 813 /** 814 * Gets a JSON object member of a JSON object. 815 * 816 * @param o The JSON object. Must not be {@code null}. 817 * @param key The JSON object member key. Must not be {@code null}. 818 * 819 * @return The member value. 820 * 821 * @throws ParseException If the value is missing, {@code null} or not 822 * of the expected type. 823 */ 824 public static JSONObject getJSONObject(final JSONObject o, final String key) 825 throws ParseException { 826 827 return getGeneric(o, key, JSONObject.class); 828 } 829 830 831 /** 832 * Gets a JSON object member of a JSON object. 833 * 834 * @param o The JSON object. Must not be {@code null}. 835 * @param key The JSON object member key. Must not be {@code null}. 836 * @param def The default value to return if the key is not present or 837 * the value is {@code null}. May be {@code null}. 838 * 839 * @return The member value. 840 * 841 * @throws ParseException If the value is not of the expected type. 842 */ 843 public static JSONObject getJSONObject(final JSONObject o, final String key, final JSONObject def) 844 throws ParseException { 845 846 if (o.get(key) != null) { 847 return getJSONObject(o, key); 848 } 849 850 return def; 851 } 852 853 854 /** 855 * Prevents public instantiation. 856 */ 857 private JSONObjectUtils() {} 858} 859