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 com.nimbusds.jose.jwk.JWKSet;
022import com.nimbusds.jwt.JWTClaimsSet;
023import com.nimbusds.oauth2.sdk.ParseException;
024import net.minidev.json.JSONArray;
025import net.minidev.json.JSONObject;
026
027import java.net.MalformedURLException;
028import java.net.URI;
029import java.net.URISyntaxException;
030import java.net.URL;
031import java.util.*;
032
033
034/**
035 * JSON object helper methods for parsing and typed retrieval of member values.
036 */
037public final class JSONObjectUtils {
038        
039        
040        /**
041         * Returns {@code true} if the JSON object is defined and contains the 
042         * specified key.
043         *
044         * @param jsonObject The JSON object to check. May be {@code null}.
045         * @param key        The key to check. Must not be {@code null}.
046         *
047         * @return {@code true} if the JSON object is defined and contains the
048         *         specified key, else {@code false}.
049         */
050        public static boolean containsKey(final JSONObject jsonObject, final String key) {
051
052                return jsonObject != null && jsonObject.containsKey(key);
053        }
054        
055        
056        /**
057         * Parses a JSON object.
058         *
059         * <p>Specific JSON to Java entity mapping (as per JSON Simple):
060         *
061         * <ul>
062         *     <li>JSON numbers mapped to {@code java.lang.Number}.
063         *     <li>JSON integer numbers mapped to {@code long}.
064         *     <li>JSON fraction numbers mapped to {@code double}.
065         * </ul>
066         *
067         * @param s The JSON object string to parse. Must not be {@code null}.
068         *
069         * @return The JSON object.
070         *
071         * @throws ParseException If the string cannot be parsed to a JSON 
072         *                        object.
073         */
074        public static JSONObject parse(final String s)
075                throws ParseException {
076                
077                Object o = JSONUtils.parseJSON(s);
078                
079                if (o instanceof JSONObject)
080                        return (JSONObject)o;
081                else
082                        throw new ParseException("The JSON entity is not an object");
083        }
084        
085        
086        /**
087         * Parses a JSON object while keeping the order of JSON object members.
088         *
089         * <p>Specific JSON to Java entity mapping (as per JSON Simple):
090         *
091         * <ul>
092         *     <li>JSON numbers mapped to {@code java.lang.Number}.
093         *     <li>JSON integer numbers mapped to {@code long}.
094         *     <li>JSON fraction numbers mapped to {@code double}.
095         * </ul>
096         *
097         * @param s The JSON object string to parse. Must not be {@code null}.
098         *
099         * @return The JSON object as linked hash map.
100         *
101         * @throws ParseException If the string cannot be parsed to a JSON
102         *                        object.
103         */
104        public static LinkedHashMap<String,Object> parseKeepingOrder(final String s)
105                throws ParseException {
106                
107                Object o = JSONUtils.parseJSONKeepingOrder(s);
108                
109                if (o instanceof LinkedHashMap)
110                        return (LinkedHashMap<String,Object>)o;
111                else
112                        throw new ParseException("The JSON entity is not an object");
113        }
114
115
116        /**
117         * Use {@link #parse(String)} instead.
118         *
119         * @param s The JSON object string to parse. Must not be {@code null}.
120         *
121         * @return The JSON object.
122         *
123         * @throws ParseException If the string cannot be parsed to a JSON
124         *                        object.
125         */
126        @Deprecated
127        public static JSONObject parseJSONObject(final String s)
128                throws ParseException {
129
130                return parse(s);
131        }
132        
133        
134        /**
135         * Gets a generic member of a JSON object.
136         *
137         * @param o     The JSON object. Must not be {@code null}.
138         * @param key   The JSON object member key. Must not be {@code null}.
139         * @param clazz The expected class of the JSON object member value.
140         *              Must not be {@code null}.
141         *
142         * @return The JSON object member value.
143         *
144         * @throws ParseException If the value is missing, {@code null} or not
145         *                        of the expected type.
146         */
147        public static <T> T getGeneric(final JSONObject o, final String key, final Class<T> clazz)
148                throws ParseException {
149        
150                if (! o.containsKey(key))
151                        throw new ParseException("Missing JSON object member with key " + key);
152                
153                Object value = o.get(key);
154                
155                if (value == null) {
156                        throw new ParseException("JSON object member with key " + key + " has null value");
157                }
158                
159                try {
160                        return JSONUtils.to(value, clazz);
161                } catch (ParseException e) {
162                        throw new ParseException("Unexpected type of JSON object member with key " + key, e);
163                }
164        }
165
166
167        /**
168         * Gets a boolean member of a JSON object.
169         *
170         * @param o   The JSON object. Must not be {@code null}.
171         * @param key The JSON object member key. Must not be {@code null}.
172         *
173         * @return The member value.
174         *
175         * @throws ParseException If the value is missing, {@code null} or not
176         *                        of the expected type.
177         */
178        public static boolean getBoolean(final JSONObject o, final String key)
179                throws ParseException {
180                
181                return getGeneric(o, key, Boolean.class);
182        }
183
184
185        /**
186         * Gets a boolean member of a JSON object.
187         *
188         * @param o   The JSON object. Must not be {@code null}.
189         * @param key The JSON object member key. Must not be {@code null}.
190         * @param def The default value to return if the key is not present or.
191         *            the value is {@code null}. May be {@code null}.
192         *
193         * @return The member value.
194         *
195         * @throws ParseException If the value is not of the expected type.
196         */
197        public static boolean getBoolean(final JSONObject o, final String key, final boolean def)
198                throws ParseException {
199                
200                if (o.get(key) != null) {
201                        return getBoolean(o, key);
202                }
203                
204                return def;
205        }
206        
207        
208        /**
209         * Gets an number member of a JSON object as {@code int}.
210         *
211         * @param o   The JSON object. Must not be {@code null}.
212         * @param key The JSON object member key. Must not be {@code null}.
213         *
214         * @return The member value.
215         *
216         * @throws ParseException If the value is missing, {@code null} or not
217         *                        of the expected type.
218         */
219        public static int getInt(final JSONObject o, final String key)
220                throws ParseException {
221                
222                return getGeneric(o, key, Number.class).intValue();     
223        }
224        
225        
226        /**
227         * Gets an number member of a JSON object as {@code int}.
228         *
229         * @param o   The JSON object. Must not be {@code null}.
230         * @param key The JSON object member key. Must not be {@code null}.
231         * @param def The default value to return if the key is not present or
232         *            the value is {@code null}.
233         *
234         * @return The member value.
235         *
236         * @throws ParseException If the value is not of the expected type.
237         */
238        public static int getInt(final JSONObject o, final String key, final int def)
239                throws ParseException {
240                
241                if (o.get(key) != null) {
242                        return getInt(o, key);
243                }
244                
245                return def;
246        }
247        
248        
249        /**
250         * Gets a number member of a JSON object as {@code long}.
251         *
252         * @param o   The JSON object. Must not be {@code null}.
253         * @param key The JSON object member key. Must not be {@code null}.
254         *
255         * @return The member value.
256         *
257         * @throws ParseException If the value is missing, {@code null} or not
258         *                        of the expected type.
259         */
260        public static long getLong(final JSONObject o, final String key)
261                throws ParseException {
262                
263                return getGeneric(o, key, Number.class).longValue();
264        }
265        
266        
267        /**
268         * Gets a number member of a JSON object as {@code long}.
269         *
270         * @param o   The JSON object. Must not be {@code null}.
271         * @param key The JSON object member key. Must not be {@code null}.
272         * @param def The default value to return if the key is not present or
273         *            the value is {@code null}.
274         *
275         * @return The member value.
276         *
277         * @throws ParseException If the value is not of the expected type.
278         */
279        public static long getLong(final JSONObject o, final String key, final long def)
280                throws ParseException {
281                
282                if (o.get(key) != null) {
283                        return getLong(o, key);
284                }
285                
286                return def;
287        }
288
289
290        /**
291         * Gets a number member of a JSON object as a non-negative
292         * {@code long}.
293         *
294         * @param o   The JSON object. Must not be {@code null}.
295         * @param key The JSON object member key. Must not be {@code null}.
296         *
297         * @return The member value.
298         *
299         * @throws ParseException If the value is missing, {@code null} or not
300         *                        of the expected type or sign.
301         */
302        public static long getNonNegativeLong(final JSONObject o, final String key)
303                throws ParseException {
304
305                return ensureNonNegative(key, getLong(o, key));
306        }
307
308
309        /**
310         * Gets a number member of a JSON object as a non-negative
311         * {@code long}.
312         *
313         * @param o   The JSON object. Must not be {@code null}.
314         * @param key The JSON object member key. Must not be {@code null}.
315         * @param def The default value to return if the key is not present or
316         *            the value is {@code null}. Must not be negative.
317         *
318         * @return The member value.
319         *
320         * @throws ParseException If the value is not of the expected type or
321         *                        sign.
322         */
323        public static long getNonNegativeLong(final JSONObject o, final String key, final long def)
324                throws ParseException {
325
326                return ensureNonNegative(key, getLong(o, key, def));
327        }
328
329
330        private static long ensureNonNegative(final String key, final long v)
331                throws ParseException{
332                if (v < 0) {
333                        throw new ParseException("JSON object member with key " + key + " has negative value");
334                }
335                return v;
336        }
337        
338        
339        /**
340         * Gets a number member of a JSON object {@code float}.
341         *
342         * @param o   The JSON object. Must not be {@code null}.
343         * @param key The JSON object member key. Must not be {@code null}.
344         *
345         * @return The member value.
346         *
347         * @throws ParseException If the value is missing, {@code null} or not
348         *                        of the expected type.
349         */
350        public static float getFloat(final JSONObject o, final String key)
351                throws ParseException {
352                
353                return getGeneric(o, key, Number.class).floatValue();
354        }
355        
356        
357        /**
358         * Gets a number member of a JSON object {@code float}.
359         *
360         * @param o   The JSON object. Must not be {@code null}.
361         * @param key The JSON object member key. Must not be {@code null}.
362         * @param def The default value to return if the key is not present or
363         *            the value is {@code null}.
364         *
365         * @return The member value.
366         *
367         * @throws ParseException If the value is not of the expected type.
368         */
369        public static float getFloat(final JSONObject o, final String key, final float def)
370                throws ParseException {
371                
372                if (o.get(key) != null) {
373                        return getFloat(o, key);
374                }
375                
376                return def;
377        }
378        
379        
380        /**
381         * Gets a number member of a JSON object as {@code double}.
382         *
383         * @param o   The JSON object. Must not be {@code null}.
384         * @param key The JSON object member key. Must not be {@code null}.
385         *
386         * @return The member value.
387         *
388         * @throws ParseException If the value is missing, {@code null} or not
389         *                        of the expected type.
390         */
391        public static double getDouble(final JSONObject o, final String key)
392                throws ParseException {
393                
394                return getGeneric(o, key, Number.class).doubleValue();
395        }
396        
397        
398        /**
399         * Gets a number member of a JSON object as {@code double}.
400         *
401         * @param o   The JSON object. Must not be {@code null}.
402         * @param key The JSON object member key. Must not be {@code null}.
403         * @param def The default value to return if the key is not present or
404         *            the value is {@code null}.
405         *
406         * @return The member value.
407         *
408         * @throws ParseException If the value is not of the expected type.
409         */
410        public static double getDouble(final JSONObject o, final String key, final double def)
411                throws ParseException {
412                
413                if (o.get(key) != null) {
414                        return getDouble(o, key);
415                }
416                
417                return def;
418        }
419
420
421        /**
422         * Gets a number member of a JSON object as {@code java.lang.Number}.
423         *
424         * @param o   The JSON object. Must not be {@code null}.
425         * @param key The JSON object member key. Must not be {@code null}.
426         *
427         * @return The member value.
428         *
429         * @throws ParseException If the value is missing, {@code null} or not
430         *                        of the expected type.
431         */
432        public static Number getNumber(final JSONObject o, final String key)
433                throws ParseException {
434
435                return getGeneric(o, key, Number.class);
436        }
437
438
439        /**
440         * Gets a number member of a JSON object as {@code java.lang.Number}.
441         *
442         * @param o   The JSON object. Must not be {@code null}.
443         * @param key The JSON object member key. Must not be {@code null}.
444         * @param def The default value to return if the key is not present or
445         *            the value is {@code null}. May be {@code null}.
446         *
447         * @return The member value.
448         *
449         * @throws ParseException If the value is not of the expected type.
450         */
451        public static Number getNumber(final JSONObject o, final String key, final Number def)
452                throws ParseException {
453
454                if (o.get(key) != null) {
455                        return getNumber(o, key);
456                }
457                
458                return def;
459        }
460        
461        
462        /**
463         * Gets a string member of a JSON object.
464         *
465         * @param o   The JSON object. Must not be {@code null}.
466         * @param key The JSON object member key. Must not be {@code null}.
467         *
468         * @return The member value.
469         *
470         * @throws ParseException If the value is missing, {@code null} or not
471         *                        of the expected type.
472         */
473        public static String getString(final JSONObject o, final String key)
474                throws ParseException {
475                
476                return getGeneric(o, key, String.class);
477        }
478        
479        
480        /**
481         * Gets a string member of a JSON object.
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         * @param def The default value to return if the key is not present or
486         *            the value is {@code null}. May be {@code null}.
487         *
488         * @return The member value.
489         *
490         * @throws ParseException If the value is not of the expected type.
491         */
492        public static String getString(final JSONObject o, final String key, final String def)
493                throws ParseException {
494                
495                if (o.get(key) != null) {
496                        return getString(o, key);
497                }
498                
499                return def;
500        }
501
502
503        /**
504         * Gets a string member of a JSON object.
505         *
506         * @param o   The JSON object. Must not be {@code null}.
507         * @param key The JSON object member key. Must not be {@code null}.
508         *
509         * @return The member value.
510         *
511         * @throws ParseException If the value is missing, {@code null}, not of
512         *                        the expected type, empty or blank.
513         */
514        public static String getNonBlankString(final JSONObject o, final String key)
515                throws ParseException {
516
517                String value = getString(o, key);
518                if (StringUtils.isBlank(value)) {
519                        throw new ParseException("Empty or blank JSON object member with key " + key);
520                }
521                return value;
522        }
523
524
525        /**
526         * Gets a string member of a JSON object as an enumerated object.
527         *
528         * @param o         The JSON object. Must not be {@code null}.
529         * @param key       The JSON object member key. Must not be
530         *                  {@code null}.
531         * @param enumClass The enumeration class. 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 <T extends Enum<T>> T getEnum(final JSONObject o, 
539                                                    final String key,
540                                                    final Class<T> enumClass)
541                throws ParseException {
542
543                String value = getString(o, key);
544
545                for (T en: enumClass.getEnumConstants()) {
546                               
547                        if (en.toString().equalsIgnoreCase(value))
548                                return en;
549                }
550
551                throw new ParseException("Unexpected value of JSON object member with key " + key);
552        }
553
554
555        /**
556         * Gets a string member of a JSON object as an enumerated object.
557         *
558         * @param o         The JSON object. Must not be {@code null}.
559         * @param key       The JSON object member key. Must not be
560         *                  {@code null}.
561         * @param enumClass The enumeration class. Must not be {@code null}.
562         * @param def       The default value to return if the key is not
563         *                  present or the value is {@code null}. May be
564         *                  {@code null}.
565         *
566         * @return The member value.
567         *
568         * @throws ParseException If the value is not of the expected type.
569         */
570        public static <T extends Enum<T>> T getEnum(final JSONObject o,
571                                                    final String key,
572                                                    final Class<T> enumClass,
573                                                    final T def)
574                throws ParseException {
575
576                if (o.get(key) != null) {
577                        return getEnum(o, key, enumClass);
578                }
579                
580                return def;
581        }
582
583
584        /**
585         * Gets a string member of a JSON object as {@code java.net.URI}.
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 URI getURI(final JSONObject o, final String key)
596                throws ParseException {
597
598                try {
599                        return new URI(getGeneric(o, key, String.class));
600
601                } catch (URISyntaxException e) {
602
603                        throw new ParseException(e.getMessage(), e);
604                }
605        }
606
607
608        /**
609         * Gets a string member of a JSON object as {@code java.net.URI}.
610         *
611         * @param o   The JSON object. Must not be {@code null}.
612         * @param key The JSON object member key. Must not be {@code null}.
613         * @param def The default value to return if the key is not present or
614         *            the value is {@code null}. May be {@code null}.
615         *
616         * @return The member value.
617         *
618         * @throws ParseException If the value is not of the expected type.
619         */
620        public static URI getURI(final JSONObject o, final String key, final URI def)
621                throws ParseException {
622
623                if (o.get(key) != null) {
624                        return getURI(o, key);
625                }
626                
627                return def;
628        }
629        
630        
631        /**
632         * Gets a string member of a JSON object as {@code java.net.URL}.
633         *
634         * @param o   The JSON object. Must not be {@code null}.
635         * @param key The JSON object member key. Must not be {@code null}.
636         *
637         * @return The member value.
638         *
639         * @throws ParseException If the value is missing, {@code null} or not
640         *                        of the expected type.
641         */
642        public static URL getURL(final JSONObject o, final String key)
643                throws ParseException {
644                
645                try {
646                        return new URL(getGeneric(o, key, String.class));
647                        
648                } catch (MalformedURLException e) {
649                
650                        throw new ParseException(e.getMessage(), e);
651                }
652        }
653        
654        
655        /**
656         * Gets a string member of a JSON object as {@code java.net.URL}.
657         *
658         * @param o   The JSON object. Must not be {@code null}.
659         * @param key The JSON object member key. Must not be {@code null}.
660         * @param def The default value to return if the key is not present or
661         *            the value is {@code null}. May be {@code null}.
662         *
663         * @return The member value.
664         *
665         * @throws ParseException If the value is not of the expected type.
666         */
667        public static URL getURL(final JSONObject o, final String key, final URL def)
668                throws ParseException {
669                
670                if (o.get(key) != null) {
671                        return getURL(o, key);
672                }
673                
674                return def;
675        }
676        
677        
678        /**
679         * Gets a JSON array member of a JSON object.
680         *
681         * @param o   The JSON object. Must not be {@code null}.
682         * @param key The JSON object member key. Must not be {@code null}.
683         *
684         * @return The member value.
685         *
686         * @throws ParseException If the value is missing, {@code null} or not
687         *                        of the expected type.
688         */
689        public static JSONArray getJSONArray(final JSONObject o, final String key)
690                throws ParseException {
691                
692                List<?> list = getGeneric(o, key, List.class);
693                JSONArray jsonArray = new JSONArray();
694                jsonArray.addAll(list);
695                return jsonArray;
696        }
697        
698        
699        /**
700         * Gets a JSON array member of a JSON object.
701         *
702         * @param o   The JSON object. Must not be {@code null}.
703         * @param key The JSON object member key. Must not be {@code null}.
704         * @param def The default value to return if the key is not present or
705         *            the value is {@code null}. May be {@code null}.
706         *
707         * @return The member value.
708         *
709         * @throws ParseException If the value is not of the expected type.
710         */
711        public static JSONArray getJSONArray(final JSONObject o, final String key, final JSONArray def)
712                throws ParseException {
713                
714                if (o.get(key) != null) {
715                        return getJSONArray(o, key);
716                }
717                
718                return def;
719        }
720
721
722        /**
723         * Gets a list member of a JSON object.
724         *
725         * @param o   The JSON object. Must not be {@code null}.
726         * @param key The JSON object member key. Must not be {@code null}.
727         *
728         * @return The member value.
729         *
730         * @throws ParseException If the value is missing, {@code null} or not
731         *                        of the expected type.
732         */
733        @SuppressWarnings("unchecked")
734        public static List<Object> getList(final JSONObject o, final String key)
735                throws ParseException {
736                
737                return getGeneric(o, key, List.class);
738        }
739
740
741        /**
742         * Gets a list member of a JSON object.
743         *
744         * @param o   The JSON object. Must not be {@code null}.
745         * @param key The JSON object member key. Must not be {@code null}.
746         * @param def The default value to return if the key is not present or
747         *            the value is {@code null}. May be {@code null}.
748         *
749         * @return The member value.
750         *
751         * @throws ParseException If the value is not of the expected type.
752         */
753        public static List<Object> getList(final JSONObject o, final String key, final List<Object> def)
754                throws ParseException {
755                
756                if (o.get(key) != null) {
757                        return getList(o, key);
758                }
759                
760                return def;
761        }
762
763
764        /**
765         * Gets a string array member of a JSON object.
766         *
767         * @param o   The JSON object. Must not be {@code null}.
768         * @param key The JSON object member key. Must not be {@code null}.
769         *
770         * @return The member value.
771         *
772         * @throws ParseException If the value is missing, {@code null} or not
773         *                        of the expected type.
774         */
775        public static String[] getStringArray(final JSONObject o, final String key)
776                throws ParseException {
777
778                List<Object> list = getList(o, key);
779
780                try {
781                        return list.toArray(new String[0]);
782
783                } catch (ArrayStoreException e) {
784
785                        throw new ParseException("JSON object member with key " + key + " is not an array of strings");
786                }
787        }
788
789
790        /**
791         * Gets a string array member of a JSON object.
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 String[] getStringArray(final JSONObject o, final String key, final String[] def)
803                throws ParseException {
804
805                if (o.get(key) != null) {
806                        return getStringArray(o, key);
807                }
808                
809                return def;
810        }
811
812
813        /**
814         * Gets a string list 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 List<String> getStringList(final JSONObject o, final String key)
825                throws ParseException {
826
827                return Arrays.asList(getStringArray(o, key));
828        }
829
830
831        /**
832         * Gets a string list 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 List<String> getStringList(final JSONObject o, final String key, final List<String> def)
844                throws ParseException {
845
846                if (o.get(key) != null) {
847                        return getStringList(o, key);
848                }
849                
850                return def;
851        }
852
853
854        /**
855         * Gets a string array member of a JSON object as a string set.
856         *
857         * @param o   The JSON object. Must not be {@code null}.
858         * @param key The JSON object member key. Must not be {@code null}.
859         *
860         * @return The member value.
861         *
862         * @throws ParseException If the value is missing, {@code null} or not
863         *                        of the expected type.
864         */
865        public static Set<String> getStringSet(final JSONObject o, final String key)
866                throws ParseException {
867
868                List<Object> list = getList(o, key);
869
870                Set<String> set = new HashSet<>();
871
872                for (Object item: list) {
873
874                        try {
875                                set.add((String)item);
876
877                        } catch (Exception e) {
878
879                                throw new ParseException("JSON object member with key " + key + " is not an array of strings");
880                        }
881
882                }
883
884                return set;
885        }
886
887
888        /**
889         * Gets a string array member of a JSON object as a string set.
890         *
891         * @param o   The JSON object. Must not be {@code null}.
892         * @param key The JSON object member key. Must not be {@code null}.
893         * @param def The default value to return if the key is not present or
894         *            the value is {@code null}. May be {@code null}.
895         *
896         * @return The member value.
897         *
898         * @throws ParseException If the value is not of the expected type.
899         */
900        public static Set<String> getStringSet(final JSONObject o, final String key, final Set<String> def)
901                throws ParseException {
902
903                if (o.get(key) != null) {
904                        return getStringSet(o, key);
905                }
906                
907                return def;
908        }
909        
910        
911        /**
912         * Gets a JSON object member of a JSON object.
913         *
914         * @param o   The JSON object. Must not be {@code null}.
915         * @param key The JSON object member key. Must not be {@code null}.
916         *
917         * @return The member value.
918         *
919         * @throws ParseException If the value is missing, {@code null} or not
920         *                        of the expected type.
921         */
922        public static JSONObject getJSONObject(final JSONObject o, final String key)
923                throws ParseException {
924                
925                @SuppressWarnings("unchecked")
926                Map<String, ?> mapObject = getGeneric(o, key, Map.class);
927                return new JSONObject(mapObject);
928        }
929        
930        
931        /**
932         * Gets a JSON object member of a JSON object.
933         *
934         * @param o   The JSON object. Must not be {@code null}.
935         * @param key The JSON object member key. Must not be {@code null}.
936         * @param def The default value to return if the key is not present or
937         *            the value is {@code null}. May be {@code null}.
938         *
939         * @return The member value.
940         *
941         * @throws ParseException If the value is not of the expected type.
942         */
943        public static JSONObject getJSONObject(final JSONObject o, final String key, final JSONObject def)
944                throws ParseException {
945                
946                if (o.get(key) != null) {
947                        return getJSONObject(o, key);
948                }
949                
950                return def;
951        }
952        
953        
954        /**
955         * Returns the JSON object representation of the specified JWT claims
956         * set.
957         *
958         * @param jwtClaimsSet The JWT claims set, {@code null} if not
959         *                     specified.
960         *
961         * @return The JSON object, {@code null} if not specified.
962         */
963        public static JSONObject toJSONObject(final JWTClaimsSet jwtClaimsSet) {
964                
965                if (jwtClaimsSet == null) {
966                        return null;
967                }
968                
969                if (jwtClaimsSet.getClaims().isEmpty()) {
970                        return new JSONObject();
971                }
972                
973                // Serialise and parse is the safest method
974                final String json = jwtClaimsSet.toString();
975                
976                try {
977                        return parse(json);
978                } catch (ParseException e) {
979                        // Should never happen
980                        return null;
981                }
982        }
983        
984        
985        /**
986         * Returns the JSON object representation of the specified JWK set.
987         *
988         * @param jwkSet The JWK set, {@code null} if not specified.
989         *
990         * @return The JSON object, {@code null} if not specified.
991         */
992        public static JSONObject toJSONObject(final JWKSet jwkSet) {
993                
994                if (jwkSet == null) {
995                        return null;
996                }
997                
998                // Serialise and parse is the safest method
999                final String json = jwkSet.toString(false);
1000                
1001                try {
1002                        return parse(json);
1003                } catch (ParseException e) {
1004                        // Should never happen
1005                        return null;
1006                }
1007        }
1008        
1009
1010        /**
1011         * Prevents public instantiation.
1012         */
1013        private JSONObjectUtils() {}
1014}
1015