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