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