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