001 package com.nimbusds.oauth2.sdk.util;
002
003
004 import java.net.MalformedURLException;
005 import java.net.URL;
006
007 import java.util.List;
008
009 import javax.mail.internet.AddressException;
010 import javax.mail.internet.InternetAddress;
011
012 import net.minidev.json.JSONArray;
013 import net.minidev.json.JSONObject;
014
015 import net.minidev.json.parser.JSONParser;
016
017 import com.nimbusds.oauth2.sdk.ParseException;
018
019
020 /**
021 * JSON object helper methods for parsing and typed retrieval of member values.
022 *
023 * @author Vladimir Dzhuvinov
024 * @version $version$ (2013-01-28)
025 */
026 public class JSONObjectUtils {
027
028
029 /**
030 * Returns {@code true} if the JSON object is defined and contains the
031 * specified key.
032 *
033 * @param jsonObject The JSON object to check. May be {@code null}.
034 * @param key The key to check. Must not be {@code null}.
035 *
036 * @return {@code true} if the JSON object is defined and contains the
037 * specified key, else {@code false}.
038 */
039 public static boolean containsKey(final JSONObject jsonObject, final String key) {
040
041 if (jsonObject != null && jsonObject.containsKey(key))
042 return true;
043 else
044 return false;
045 }
046
047
048 /**
049 * Parses a JSON object.
050 *
051 * <p>Specific JSON to Java entity mapping (as per JSON Simple):
052 *
053 * <ul>
054 * <li>JSON numbers mapped to {@code java.lang.Number}.
055 * <li>JSON integer numbers mapped to {@code long}.
056 * <li>JSON fraction numbers mapped to {@code double}.
057 * </ul>
058 *
059 * @param s The JSON object string to parse. Must not be {@code null}.
060 *
061 * @return The JSON object.
062 *
063 * @throws ParseException If the string cannot be parsed to a JSON
064 * object.
065 */
066 public static JSONObject parseJSONObject(final String s)
067 throws ParseException {
068
069 Object o = null;
070
071 try {
072 o = new JSONParser(JSONParser.USE_HI_PRECISION_FLOAT).parse(s);
073
074 } catch (net.minidev.json.parser.ParseException e) {
075
076 throw new ParseException("Invalid JSON: " + e.getMessage(), e);
077 }
078
079 if (o instanceof JSONObject)
080 return (JSONObject)o;
081 else
082 throw new ParseException("JSON entity is not an object");
083 }
084
085
086 /**
087 * Gets a generic member of a JSON object.
088 *
089 * @param o The JSON object. Must not be {@code null}.
090 * @param key The JSON object member key. Must not be {@code null}.
091 * @param clazz The expected class of the JSON object member value. Must
092 * not be {@code null}.
093 *
094 * @return The JSON object member value.
095 *
096 * @throws ParseException If the value is missing, {@code null} or not
097 * of the expected type.
098 */
099 @SuppressWarnings("unchecked")
100 private static <T> T getGeneric(final JSONObject o, final String key, final Class<T> clazz)
101 throws ParseException {
102
103 if (! o.containsKey(key))
104 throw new ParseException("Missing JSON object member with key \"" + key + "\"");
105
106 if (o.get(key) == null)
107 throw new ParseException("JSON object member with key \"" + key + "\" has null value");
108
109 Object value = o.get(key);
110
111 if (! clazz.isAssignableFrom(value.getClass()))
112 throw new ParseException("Unexpected type of JSON object member with key \"" + key + "\"");
113
114 return (T)value;
115 }
116
117
118 /**
119 * Gets a boolean member of a JSON object.
120 *
121 * @param o The JSON object. Must not be {@code null}.
122 * @param key The JSON object member key. Must not be {@code null}.
123 *
124 * @return The member value.
125 *
126 * @throws ParseException If the value is missing, {@code null} or not
127 * of the expected type.
128 */
129 public static boolean getBoolean(final JSONObject o, final String key)
130 throws ParseException {
131
132 return getGeneric(o, key, Boolean.class);
133 }
134
135
136 /**
137 * Gets an number member of a JSON object as {@code int}.
138 *
139 * @param o The JSON object. Must not be {@code null}.
140 * @param key The JSON object member key. Must not be {@code null}.
141 *
142 * @return The member value.
143 *
144 * @throws ParseException If the value is missing, {@code null} or not
145 * of the expected type.
146 */
147 public static int getInt(final JSONObject o, final String key)
148 throws ParseException {
149
150 return getGeneric(o, key, Number.class).intValue();
151 }
152
153
154 /**
155 * Gets a number member of a JSON object as {@code long}.
156 *
157 * @param o The JSON object. Must not be {@code null}.
158 * @param key The JSON object member key. Must not be {@code null}.
159 *
160 * @return The member value.
161 *
162 * @throws ParseException If the value is missing, {@code null} or not
163 * of the expected type.
164 */
165 public static long getLong(final JSONObject o, final String key)
166 throws ParseException {
167
168 return getGeneric(o, key, Number.class).longValue();
169 }
170
171
172 /**
173 * Gets a number member of a JSON object {@code float}.
174 *
175 * @param o The JSON object. Must not be {@code null}.
176 * @param key The JSON object member key. Must not be {@code null}.
177 *
178 * @return The member value.
179 *
180 * @throws ParseException If the value is missing, {@code null} or not
181 * of the expected type.
182 */
183 public static float getFloat(final JSONObject o, final String key)
184 throws ParseException {
185
186 return getGeneric(o, key, Number.class).floatValue();
187 }
188
189
190 /**
191 * Gets a number member of a JSON object as {@code double}.
192 *
193 * @param o The JSON object. Must not be {@code null}.
194 * @param key The JSON object member key. Must not be {@code null}.
195 *
196 * @return The member value.
197 *
198 * @throws ParseException If the value is missing, {@code null} or not
199 * of the expected type.
200 */
201 public static double getDouble(final JSONObject o, final String key)
202 throws ParseException {
203
204 return getGeneric(o, key, Number.class).doubleValue();
205 }
206
207
208 /**
209 * Gets a string member of a JSON object.
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 String getString(final JSONObject o, final String key)
220 throws ParseException {
221
222 return getGeneric(o, key, String.class);
223 }
224
225
226 /**
227 * Gets a string member of a JSON object as an enumerated object.
228 *
229 * @param o The JSON object. Must not be {@code null}.
230 * @param key The JSON object member key. Must not be
231 * {@code null}.
232 * @param enumClass The enumeration class. Must not be {@code null}.
233 *
234 * @return The member value.
235 *
236 * @throws ParseException If the value is missing, {@code null} or not
237 * of the expected type.
238 */
239 public static <T extends Enum<T>> T getEnum(final JSONObject o,
240 final String key,
241 final Class<T> enumClass)
242 throws ParseException {
243
244 String value = getString(o, key);
245
246 for (T en: enumClass.getEnumConstants()) {
247
248 if (en.toString().equalsIgnoreCase(value))
249 return en;
250 }
251
252 throw new ParseException("Unexpected value of JSON object member with key \"" + key + "\"");
253 }
254
255
256 /**
257 * Gets a string member of a JSON object as {@code java.net.URL}.
258 *
259 * @param o The JSON object. Must not be {@code null}.
260 * @param key The JSON object member key. Must not be {@code null}.
261 *
262 * @return The member value.
263 *
264 * @throws ParseException If the value is missing, {@code null} or not
265 * of the expected type.
266 */
267 public static URL getURL(final JSONObject o, final String key)
268 throws ParseException {
269
270 try {
271 return new URL(getGeneric(o, key, String.class));
272
273 } catch (MalformedURLException e) {
274
275 throw new ParseException(e.getMessage(), e);
276 }
277 }
278
279
280 /**
281 * Gets a string member of a JSON object as
282 * {@code javax.mail.internet.InternetAddress}.
283 *
284 * @param o The JSON object. Must not be {@code null}.
285 * @param key The JSON object member key. Must not be {@code null}.
286 *
287 * @return The member value.
288 *
289 * @throws ParseException If the value is missing, {@code null} or not
290 * of the expected type.
291 */
292 public static InternetAddress getEmail(final JSONObject o, final String key)
293 throws ParseException {
294
295 try {
296 final boolean strict = true;
297
298 return new InternetAddress(getGeneric(o, key, String.class), strict);
299
300 } catch (AddressException e) {
301
302 throw new ParseException(e.getMessage(), e);
303 }
304 }
305
306
307 /**
308 * Gets a JSON array member of a JSON object.
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 *
313 * @return The member value.
314 *
315 * @throws ParseException If the value is missing, {@code null} or not
316 * of the expected type.
317 */
318 public static JSONArray getJSONArray(final JSONObject o, final String key)
319 throws ParseException {
320
321 return getGeneric(o, key, JSONArray.class);
322 }
323
324
325 /**
326 * Gets a list member of a JSON object.
327 *
328 * @param o The JSON object. Must not be {@code null}.
329 * @param key The JSON object member key. Must not be {@code null}.
330 *
331 * @return The member value.
332 *
333 * @throws ParseException If the value is missing, {@code null} or not
334 * of the expected type.
335 */
336 @SuppressWarnings("unchecked")
337 public static List<Object> getList(final JSONObject o, final String key)
338 throws ParseException {
339
340 return getGeneric(o, key, List.class);
341 }
342
343
344 /**
345 * Gets a string array member of a JSON object.
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 String[] getStringArray(final JSONObject o, final String key)
356 throws ParseException {
357
358 List<Object> list = getList(o, key);
359
360 try {
361 return list.toArray(new String[0]);
362
363 } catch (ArrayStoreException e) {
364
365 throw new ParseException("JSON object member with key \"" + key + "\" is not an array of strings");
366 }
367 }
368
369
370 /**
371 * Gets a JSON object member of a JSON object.
372 *
373 * @param o The JSON object. Must not be {@code null}.
374 * @param key The JSON object member key. Must not be {@code null}.
375 *
376 * @return The member value.
377 *
378 * @throws ParseException If the value is missing, {@code null} or not
379 * of the expected type.
380 */
381 public static JSONObject getJSONObject(final JSONObject o, final String key)
382 throws ParseException {
383
384 return getGeneric(o, key, JSONObject.class);
385 }
386
387
388 /**
389 * Prevents instantiation.
390 */
391 private JSONObjectUtils() {
392
393 // Nothing to do
394 }
395 }
396