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