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 or. 163 * the value is {@code null}. 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 (o.get(key) != null) { 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 or 204 * the value is {@code null}. 205 * 206 * @return The member value. 207 * 208 * @throws ParseException If the value is not of the expected type. 209 */ 210 public static int getInt(final JSONObject o, final String key, final int def) 211 throws ParseException { 212 213 if (o.get(key) != null) { 214 return getInt(o, key); 215 } 216 217 return def; 218 } 219 220 221 /** 222 * Gets a number member of a JSON object as {@code long}. 223 * 224 * @param o The JSON object. Must not be {@code null}. 225 * @param key The JSON object member key. Must not be {@code null}. 226 * 227 * @return The member value. 228 * 229 * @throws ParseException If the value is missing, {@code null} or not 230 * of the expected type. 231 */ 232 public static long getLong(final JSONObject o, final String key) 233 throws ParseException { 234 235 return getGeneric(o, key, Number.class).longValue(); 236 } 237 238 239 /** 240 * Gets a number member of a JSON object as {@code long}. 241 * 242 * @param o The JSON object. Must not be {@code null}. 243 * @param key The JSON object member key. Must not be {@code null}. 244 * @param def The default value to return if the key is not present or 245 * the value is {@code null}. 246 * 247 * @return The member value. 248 * 249 * @throws ParseException If the value is not of the expected type. 250 */ 251 public static long getLong(final JSONObject o, final String key, final long def) 252 throws ParseException { 253 254 if (o.get(key) != null) { 255 return getLong(o, key); 256 } 257 258 return def; 259 } 260 261 262 /** 263 * Gets a number member of a JSON object {@code float}. 264 * 265 * @param o The JSON object. Must not be {@code null}. 266 * @param key The JSON object member key. 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 float getFloat(final JSONObject o, final String key) 274 throws ParseException { 275 276 return getGeneric(o, key, Number.class).floatValue(); 277 } 278 279 280 /** 281 * Gets a number member of a JSON object {@code float}. 282 * 283 * @param o The JSON object. Must not be {@code null}. 284 * @param key The JSON object member key. Must not be {@code null}. 285 * @param def The default value to return if the key is not present or 286 * the value is {@code null}. 287 * 288 * @return The member value. 289 * 290 * @throws ParseException If the value is not of the expected type. 291 */ 292 public static float getFloat(final JSONObject o, final String key, final float def) 293 throws ParseException { 294 295 if (o.get(key) != null) { 296 return getFloat(o, key); 297 } 298 299 return def; 300 } 301 302 303 /** 304 * Gets a number member of a JSON object as {@code double}. 305 * 306 * @param o The JSON object. Must not be {@code null}. 307 * @param key The JSON object member key. Must not be {@code null}. 308 * 309 * @return The member value. 310 * 311 * @throws ParseException If the value is missing, {@code null} or not 312 * of the expected type. 313 */ 314 public static double getDouble(final JSONObject o, final String key) 315 throws ParseException { 316 317 return getGeneric(o, key, Number.class).doubleValue(); 318 } 319 320 321 /** 322 * Gets a number member of a JSON object as {@code double}. 323 * 324 * @param o The JSON object. Must not be {@code null}. 325 * @param key The JSON object member key. Must not be {@code null}. 326 * @param def The default value to return if the key is not present or 327 * the value is {@code null}. 328 * 329 * @return The member value. 330 * 331 * @throws ParseException If the value is not of the expected type. 332 */ 333 public static double getDouble(final JSONObject o, final String key, final double def) 334 throws ParseException { 335 336 if (o.get(key) != null) { 337 return getDouble(o, key); 338 } 339 340 return def; 341 } 342 343 344 /** 345 * Gets a number member of a JSON object as {@code java.lang.Number}. 346 * 347 * @param o The JSON object. Must not be {@code null}. 348 * @param key The JSON object member key. Must not be {@code null}. 349 * 350 * @return The member value. 351 * 352 * @throws ParseException If the value is missing, {@code null} or not 353 * of the expected type. 354 */ 355 public static Number getNumber(final JSONObject o, final String key) 356 throws ParseException { 357 358 return getGeneric(o, key, Number.class); 359 } 360 361 362 /** 363 * Gets a number member of a JSON object as {@code java.lang.Number}. 364 * 365 * @param o The JSON object. Must not be {@code null}. 366 * @param key The JSON object member key. Must not be {@code null}. 367 * @param def The default value to return if the key is not present or 368 * the value is {@code null}. May be {@code null}. 369 * 370 * @return The member value. 371 * 372 * @throws ParseException If the value is not of the expected type. 373 */ 374 public static Number getNumber(final JSONObject o, final String key, final Number def) 375 throws ParseException { 376 377 if (o.get(key) != null) { 378 return getNumber(o, key); 379 } 380 381 return def; 382 } 383 384 385 /** 386 * Gets a string member of a JSON object. 387 * 388 * @param o The JSON object. Must not be {@code null}. 389 * @param key The JSON object member key. Must not be {@code null}. 390 * 391 * @return The member value. 392 * 393 * @throws ParseException If the value is missing, {@code null} or not 394 * of the expected type. 395 */ 396 public static String getString(final JSONObject o, final String key) 397 throws ParseException { 398 399 return getGeneric(o, key, String.class); 400 } 401 402 403 /** 404 * Gets a string 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 * @param def The default value to return if the key is not present or 409 * the value is {@code null}. May be {@code null}. 410 * 411 * @return The member value. 412 * 413 * @throws ParseException If the value is not of the expected type. 414 */ 415 public static String getString(final JSONObject o, final String key, final String def) 416 throws ParseException { 417 418 if (o.get(key) != null) { 419 return getString(o, key); 420 } 421 422 return def; 423 } 424 425 426 /** 427 * Gets a string member of a JSON object as an enumerated object. 428 * 429 * @param o The JSON object. Must not be {@code null}. 430 * @param key The JSON object member key. Must not be 431 * {@code null}. 432 * @param enumClass The enumeration class. Must not be {@code null}. 433 * 434 * @return The member value. 435 * 436 * @throws ParseException If the value is missing, {@code null} or not 437 * of the expected type. 438 */ 439 public static <T extends Enum<T>> T getEnum(final JSONObject o, 440 final String key, 441 final Class<T> enumClass) 442 throws ParseException { 443 444 String value = getString(o, key); 445 446 for (T en: enumClass.getEnumConstants()) { 447 448 if (en.toString().equalsIgnoreCase(value)) 449 return en; 450 } 451 452 throw new ParseException("Unexpected value of JSON object member with key \"" + key + "\""); 453 } 454 455 456 /** 457 * Gets a string member of a JSON object as an enumerated object. 458 * 459 * @param o The JSON object. Must not be {@code null}. 460 * @param key The JSON object member key. Must not be 461 * {@code null}. 462 * @param enumClass The enumeration class. Must not be {@code null}. 463 * @param def The default value to return if the key is not 464 * present or the value is {@code null}. May be 465 * {@code null}. 466 * 467 * @return The member value. 468 * 469 * @throws ParseException If the value is not of the expected type. 470 */ 471 public static <T extends Enum<T>> T getEnum(final JSONObject o, 472 final String key, 473 final Class<T> enumClass, 474 final T def) 475 throws ParseException { 476 477 if (o.get(key) != null) { 478 return getEnum(o, key, enumClass); 479 } 480 481 return def; 482 } 483 484 485 /** 486 * Gets a string member of a JSON object as {@code java.net.URI}. 487 * 488 * @param o The JSON object. Must not be {@code null}. 489 * @param key The JSON object member key. Must not be {@code null}. 490 * 491 * @return The member value. 492 * 493 * @throws ParseException If the value is missing, {@code null} or not 494 * of the expected type. 495 */ 496 public static URI getURI(final JSONObject o, final String key) 497 throws ParseException { 498 499 try { 500 return new URI(getGeneric(o, key, String.class)); 501 502 } catch (URISyntaxException e) { 503 504 throw new ParseException(e.getMessage(), e); 505 } 506 } 507 508 509 /** 510 * Gets a string member of a JSON object as {@code java.net.URI}. 511 * 512 * @param o The JSON object. Must not be {@code null}. 513 * @param key The JSON object member key. Must not be {@code null}. 514 * @param def The default value to return if the key is not present or 515 * the value is {@code null}. May be {@code null}. 516 * 517 * @return The member value. 518 * 519 * @throws ParseException If the value is not of the expected type. 520 */ 521 public static URI getURI(final JSONObject o, final String key, final URI def) 522 throws ParseException { 523 524 if (o.get(key) != null) { 525 return getURI(o, key); 526 } 527 528 return def; 529 } 530 531 532 /** 533 * Gets a string member of a JSON object as {@code java.net.URL}. 534 * 535 * @param o The JSON object. Must not be {@code null}. 536 * @param key The JSON object member key. Must not be {@code null}. 537 * 538 * @return The member value. 539 * 540 * @throws ParseException If the value is missing, {@code null} or not 541 * of the expected type. 542 */ 543 public static URL getURL(final JSONObject o, final String key) 544 throws ParseException { 545 546 try { 547 return new URL(getGeneric(o, key, String.class)); 548 549 } catch (MalformedURLException e) { 550 551 throw new ParseException(e.getMessage(), e); 552 } 553 } 554 555 556 /** 557 * Gets a string member of a JSON object as 558 * {@code javax.mail.internet.InternetAddress}. 559 * 560 * @param o The JSON object. Must not be {@code null}. 561 * @param key The JSON object member key. Must not be {@code null}. 562 * 563 * @return The member value. 564 * 565 * @throws ParseException If the value is missing, {@code null} or not 566 * of the expected type. 567 */ 568 @Deprecated 569 public static InternetAddress getEmail(final JSONObject o, final String key) 570 throws ParseException { 571 572 try { 573 final boolean strict = true; 574 575 return new InternetAddress(getGeneric(o, key, String.class), strict); 576 577 } catch (AddressException e) { 578 579 throw new ParseException(e.getMessage(), e); 580 } 581 } 582 583 584 /** 585 * Gets a JSON array member of a JSON object. 586 * 587 * @param o The JSON object. Must not be {@code null}. 588 * @param key The JSON object member key. Must not be {@code null}. 589 * 590 * @return The member value. 591 * 592 * @throws ParseException If the value is missing, {@code null} or not 593 * of the expected type. 594 */ 595 public static JSONArray getJSONArray(final JSONObject o, final String key) 596 throws ParseException { 597 598 return getGeneric(o, key, JSONArray.class); 599 } 600 601 602 /** 603 * Gets a JSON array member of a JSON object. 604 * 605 * @param o The JSON object. Must not be {@code null}. 606 * @param key The JSON object member key. Must not be {@code null}. 607 * @param def The default value to return if the key is not present or 608 * the value is {@code null}. May be {@code null}. 609 * 610 * @return The member value. 611 * 612 * @throws ParseException If the value is not of the expected type. 613 */ 614 public static JSONArray getJSONArray(final JSONObject o, final String key, final JSONArray def) 615 throws ParseException { 616 617 if (o.get(key) != null) { 618 return getJSONArray(o, key); 619 } 620 621 return def; 622 } 623 624 625 /** 626 * Gets a list member of a JSON object. 627 * 628 * @param o The JSON object. Must not be {@code null}. 629 * @param key The JSON object member key. Must not be {@code null}. 630 * 631 * @return The member value. 632 * 633 * @throws ParseException If the value is missing, {@code null} or not 634 * of the expected type. 635 */ 636 @SuppressWarnings("unchecked") 637 public static List<Object> getList(final JSONObject o, final String key) 638 throws ParseException { 639 640 return getGeneric(o, key, List.class); 641 } 642 643 644 /** 645 * Gets a list member of a JSON object. 646 * 647 * @param o The JSON object. Must not be {@code null}. 648 * @param key The JSON object member key. Must not be {@code null}. 649 * @param def The default value to return if the key is not present or 650 * the value is {@code null}. May be {@code null}. 651 * 652 * @return The member value. 653 * 654 * @throws ParseException If the value is not of the expected type. 655 */ 656 @SuppressWarnings("unchecked") 657 public static List<Object> getList(final JSONObject o, final String key, final List<Object> def) 658 throws ParseException { 659 660 if (o.get(key) != null) { 661 return getList(o, key); 662 } 663 664 return def; 665 } 666 667 668 /** 669 * Gets a string array member of a JSON object. 670 * 671 * @param o The JSON object. Must not be {@code null}. 672 * @param key The JSON object member key. Must not be {@code null}. 673 * 674 * @return The member value. 675 * 676 * @throws ParseException If the value is missing, {@code null} or not 677 * of the expected type. 678 */ 679 public static String[] getStringArray(final JSONObject o, final String key) 680 throws ParseException { 681 682 List<Object> list = getList(o, key); 683 684 try { 685 return list.toArray(new String[0]); 686 687 } catch (ArrayStoreException e) { 688 689 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings"); 690 } 691 } 692 693 694 /** 695 * Gets a string array member of a JSON object. 696 * 697 * @param o The JSON object. Must not be {@code null}. 698 * @param key The JSON object member key. Must not be {@code null}. 699 * @param def The default value to return if the key is not present or 700 * the value is {@code null}. May be {@code null}. 701 * 702 * @return The member value. 703 * 704 * @throws ParseException If the value is not of the expected type. 705 */ 706 public static String[] getStringArray(final JSONObject o, final String key, final String[] def) 707 throws ParseException { 708 709 if (o.get(key) != null) { 710 return getStringArray(o, key); 711 } 712 713 return def; 714 } 715 716 717 /** 718 * Gets a string list member of a JSON object. 719 * 720 * @param o The JSON object. Must not be {@code null}. 721 * @param key The JSON object member key. Must not be {@code null}. 722 * 723 * @return The member value. 724 * 725 * @throws ParseException If the value is missing, {@code null} or not 726 * of the expected type. 727 */ 728 public static List<String> getStringList(final JSONObject o, final String key) 729 throws ParseException { 730 731 return Arrays.asList(getStringArray(o, key)); 732 } 733 734 735 /** 736 * Gets a string list member of a JSON object. 737 * 738 * @param o The JSON object. Must not be {@code null}. 739 * @param key The JSON object member key. Must not be {@code null}. 740 * @param def The default value to return if the key is not present or 741 * the value is {@code null}. May be {@code null}. 742 * 743 * @return The member value. 744 * 745 * @throws ParseException If the value is not of the expected type. 746 */ 747 public static List<String> getStringList(final JSONObject o, final String key, final List<String> def) 748 throws ParseException { 749 750 if (o.get(key) != null) { 751 return getStringList(o, key); 752 } 753 754 return def; 755 } 756 757 758 /** 759 * Gets a string array member of a JSON object as a string set. 760 * 761 * @param o The JSON object. Must not be {@code null}. 762 * @param key The JSON object member key. Must not be {@code null}. 763 * 764 * @return The member value. 765 * 766 * @throws ParseException If the value is missing, {@code null} or not 767 * of the expected type. 768 */ 769 public static Set<String> getStringSet(final JSONObject o, final String key) 770 throws ParseException { 771 772 List<Object> list = getList(o, key); 773 774 Set<String> set = new HashSet<>(); 775 776 for (Object item: list) { 777 778 try { 779 set.add((String)item); 780 781 } catch (Exception e) { 782 783 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings"); 784 } 785 786 } 787 788 return set; 789 } 790 791 792 /** 793 * Gets a string array member of a JSON object as a string set. 794 * 795 * @param o The JSON object. Must not be {@code null}. 796 * @param key The JSON object member key. Must not be {@code null}. 797 * @param def The default value to return if the key is not present or 798 * the value is {@code null}. May be {@code null}. 799 * 800 * @return The member value. 801 * 802 * @throws ParseException If the value is not of the expected type. 803 */ 804 public static Set<String> getStringSet(final JSONObject o, final String key, final Set<String> def) 805 throws ParseException { 806 807 if (o.get(key) != null) { 808 return getStringSet(o, key); 809 } 810 811 return def; 812 } 813 814 815 /** 816 * Gets a JSON object member of a JSON object. 817 * 818 * @param o The JSON object. Must not be {@code null}. 819 * @param key The JSON object member key. Must not be {@code null}. 820 * 821 * @return The member value. 822 * 823 * @throws ParseException If the value is missing, {@code null} or not 824 * of the expected type. 825 */ 826 public static JSONObject getJSONObject(final JSONObject o, final String key) 827 throws ParseException { 828 829 return getGeneric(o, key, JSONObject.class); 830 } 831 832 833 /** 834 * Gets a JSON object member of a JSON object. 835 * 836 * @param o The JSON object. Must not be {@code null}. 837 * @param key The JSON object member key. Must not be {@code null}. 838 * @param def The default value to return if the key is not present or 839 * the value is {@code null}. May be {@code null}. 840 * 841 * @return The member value. 842 * 843 * @throws ParseException If the value is not of the expected type. 844 */ 845 public static JSONObject getJSONObject(final JSONObject o, final String key, final JSONObject def) 846 throws ParseException { 847 848 if (o.get(key) != null) { 849 return getJSONObject(o, key); 850 } 851 852 return def; 853 } 854 855 856 /** 857 * Prevents public instantiation. 858 */ 859 private JSONObjectUtils() {} 860} 861