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 @SuppressWarnings("unchecked") 656 public static List<Object> getList(final JSONObject o, final String key, final List<Object> def) 657 throws ParseException { 658 659 if (o.get(key) != null) { 660 return getList(o, key); 661 } 662 663 return def; 664 } 665 666 667 /** 668 * Gets a string array member of a JSON object. 669 * 670 * @param o The JSON object. Must not be {@code null}. 671 * @param key The JSON object member key. Must not be {@code null}. 672 * 673 * @return The member value. 674 * 675 * @throws ParseException If the value is missing, {@code null} or not 676 * of the expected type. 677 */ 678 public static String[] getStringArray(final JSONObject o, final String key) 679 throws ParseException { 680 681 List<Object> list = getList(o, key); 682 683 try { 684 return list.toArray(new String[0]); 685 686 } catch (ArrayStoreException e) { 687 688 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings"); 689 } 690 } 691 692 693 /** 694 * Gets a string array member of a JSON object. 695 * 696 * @param o The JSON object. Must not be {@code null}. 697 * @param key The JSON object member key. Must not be {@code null}. 698 * @param def The default value to return if the key is not present or 699 * the value is {@code null}. May be {@code null}. 700 * 701 * @return The member value. 702 * 703 * @throws ParseException If the value is not of the expected type. 704 */ 705 public static String[] getStringArray(final JSONObject o, final String key, final String[] def) 706 throws ParseException { 707 708 if (o.get(key) != null) { 709 return getStringArray(o, key); 710 } 711 712 return def; 713 } 714 715 716 /** 717 * Gets a string list member of a JSON object. 718 * 719 * @param o The JSON object. Must not be {@code null}. 720 * @param key The JSON object member key. Must not be {@code null}. 721 * 722 * @return The member value. 723 * 724 * @throws ParseException If the value is missing, {@code null} or not 725 * of the expected type. 726 */ 727 public static List<String> getStringList(final JSONObject o, final String key) 728 throws ParseException { 729 730 return Arrays.asList(getStringArray(o, key)); 731 } 732 733 734 /** 735 * Gets a string list member of a JSON object. 736 * 737 * @param o The JSON object. Must not be {@code null}. 738 * @param key The JSON object member key. Must not be {@code null}. 739 * @param def The default value to return if the key is not present or 740 * the value is {@code null}. May be {@code null}. 741 * 742 * @return The member value. 743 * 744 * @throws ParseException If the value is not of the expected type. 745 */ 746 public static List<String> getStringList(final JSONObject o, final String key, final List<String> def) 747 throws ParseException { 748 749 if (o.get(key) != null) { 750 return getStringList(o, key); 751 } 752 753 return def; 754 } 755 756 757 /** 758 * Gets a string array member of a JSON object as a string set. 759 * 760 * @param o The JSON object. Must not be {@code null}. 761 * @param key The JSON object member key. Must not be {@code null}. 762 * 763 * @return The member value. 764 * 765 * @throws ParseException If the value is missing, {@code null} or not 766 * of the expected type. 767 */ 768 public static Set<String> getStringSet(final JSONObject o, final String key) 769 throws ParseException { 770 771 List<Object> list = getList(o, key); 772 773 Set<String> set = new HashSet<>(); 774 775 for (Object item: list) { 776 777 try { 778 set.add((String)item); 779 780 } catch (Exception e) { 781 782 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings"); 783 } 784 785 } 786 787 return set; 788 } 789 790 791 /** 792 * Gets a string array member of a JSON object as a string set. 793 * 794 * @param o The JSON object. Must not be {@code null}. 795 * @param key The JSON object member key. Must not be {@code null}. 796 * @param def The default value to return if the key is not present or 797 * the value is {@code null}. May be {@code null}. 798 * 799 * @return The member value. 800 * 801 * @throws ParseException If the value is not of the expected type. 802 */ 803 public static Set<String> getStringSet(final JSONObject o, final String key, final Set<String> def) 804 throws ParseException { 805 806 if (o.get(key) != null) { 807 return getStringSet(o, key); 808 } 809 810 return def; 811 } 812 813 814 /** 815 * Gets a JSON object member of a JSON object. 816 * 817 * @param o The JSON object. Must not be {@code null}. 818 * @param key The JSON object member key. Must not be {@code null}. 819 * 820 * @return The member value. 821 * 822 * @throws ParseException If the value is missing, {@code null} or not 823 * of the expected type. 824 */ 825 public static JSONObject getJSONObject(final JSONObject o, final String key) 826 throws ParseException { 827 828 return getGeneric(o, key, JSONObject.class); 829 } 830 831 832 /** 833 * Gets a JSON object member of a JSON object. 834 * 835 * @param o The JSON object. Must not be {@code null}. 836 * @param key The JSON object member key. Must not be {@code null}. 837 * @param def The default value to return if the key is not present or 838 * the value is {@code null}. May be {@code null}. 839 * 840 * @return The member value. 841 * 842 * @throws ParseException If the value is not of the expected type. 843 */ 844 public static JSONObject getJSONObject(final JSONObject o, final String key, final JSONObject def) 845 throws ParseException { 846 847 if (o.get(key) != null) { 848 return getJSONObject(o, key); 849 } 850 851 return def; 852 } 853 854 855 /** 856 * Prevents public instantiation. 857 */ 858 private JSONObjectUtils() {} 859} 860