001/******************************************************************************* 002 * Copyright (c) 2013, 2017 EclipseSource. 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining a copy 005 * of this software and associated documentation files (the "Software"), to deal 006 * in the Software without restriction, including without limitation the rights 007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 008 * copies of the Software, and to permit persons to whom the Software is 009 * furnished to do so, subject to the following conditions: 010 * 011 * The above copyright notice and this permission notice shall be included in all 012 * copies or substantial portions of the Software. 013 * 014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 020 * SOFTWARE. 021 ******************************************************************************/ 022package com.restfb.json; 023 024import java.io.*; 025import java.util.Objects; 026 027/** 028 * Represents a JSON value. This can be a JSON <strong>object</strong>, an <strong> array</strong>, a 029 * <strong>number</strong>, a <strong>string</strong>, or one of the literals 030 * <strong>true</strong>, <strong>false</strong>, and <strong>null</strong>. 031 * <p> 032 * The literals <strong>true</strong>, <strong>false</strong>, and <strong>null</strong> are 033 * represented by the constants {@link Json#TRUE}, {@link Json#FALSE}, and {@link Json#NULL}. 034 * </p> 035 * <p> 036 * JSON <strong>objects</strong> and <strong>arrays</strong> are represented by the subtypes 037 * {@link JsonObject} and {@link JsonArray}. Instances of these types can be created using the public constructors of these classes. 038 * </p> 039 * <p> 040 * Instances that represent JSON <strong>numbers</strong>, <strong>strings</strong> and 041 * <strong>boolean</strong> values can be created using the static factory methods 042 * {@link Json#value(String)}, {@link Json#value(long)}, {@link Json#value(double)}, etc. 043 * </p> 044 * <p> 045 * In order to find out whether an instance of this class is of a certain type, the methods 046 * {@link #isObject()}, {@link #isArray()}, {@link #isString()}, {@link #isNumber()} etc. can be used. 047 * </p> 048 * <p> 049 * If the type of a JSON value is known, the methods {@link #asObject()}, {@link #asArray()}, {@link #asString()}, 050 * {@link #asInt()}, etc. can be used to get this value directly in the appropriate target type. 051 * </p> 052 * <p> 053 * This class is <strong>not supposed to be extended</strong> by clients. 054 * </p> 055 */ 056@SuppressWarnings("serial") // use default serial UID 057public abstract class JsonValue implements Serializable { 058 059 // String constants 060 private static final String NOT_A_NUMBER = "Not a number: "; 061 private static final String NOT_A_STRING = "Not a string: "; 062 private static final String NOT_A_BOOLEAN = "Not a boolean: "; 063 // String constants 064 protected static final String STRING_IS_NULL = "string is null"; 065 protected static final String OBJECT_IS_NULL = "object is null"; 066 protected static final String NAME_IS_NULL = "name is null"; 067 protected static final String VALUE_IS_NULL = "value is null"; 068 protected static final String ARRAY_IS_NULL = "array is null"; 069 070 JsonValue() { 071 // prevent subclasses outside of this package 072 } 073 074 /** 075 * Detects whether this value represents a JSON object. If this is the case, this value is an instance of 076 * {@link JsonObject}. 077 * 078 * @return <code>true</code> if this value is an instance of JsonObject 079 */ 080 public boolean isObject() { 081 return false; 082 } 083 084 /** 085 * Detects whether this value represents a JSON array. If this is the case, this value is an instance of 086 * {@link JsonArray}. 087 * 088 * @return <code>true</code> if this value is an instance of JsonArray 089 */ 090 public boolean isArray() { 091 return false; 092 } 093 094 /** 095 * Detects whether this value represents a JSON number. 096 * 097 * @return <code>true</code> if this value represents a JSON number 098 */ 099 public boolean isNumber() { 100 return false; 101 } 102 103 /** 104 * Detects whether this value represents a JSON string. 105 * 106 * @return <code>true</code> if this value represents a JSON string 107 */ 108 public boolean isString() { 109 return false; 110 } 111 112 /** 113 * Detects whether this value represents a boolean value. 114 * 115 * @return <code>true</code> if this value represents either the JSON literal <code>true</code> or <code>false</code> 116 */ 117 public boolean isBoolean() { 118 return false; 119 } 120 121 /** 122 * Detects whether this value represents the JSON literal <code>true</code>. 123 * 124 * @return <code>true</code> if this value represents the JSON literal <code>true</code> 125 */ 126 public boolean isTrue() { 127 return false; 128 } 129 130 /** 131 * Detects whether this value represents the JSON literal <code>false</code>. 132 * 133 * @return <code>true</code> if this value represents the JSON literal <code>false</code> 134 */ 135 public boolean isFalse() { 136 return false; 137 } 138 139 /** 140 * Detects whether this value represents the JSON literal <code>null</code>. 141 * 142 * @return <code>true</code> if this value represents the JSON literal <code>null</code> 143 */ 144 public boolean isNull() { 145 return false; 146 } 147 148 /** 149 * Returns this JSON value as {@link JsonObject}, assuming that this value represents a JSON object. If this is not 150 * the case, an exception is thrown. 151 * 152 * @return a JSONObject for this value 153 * @throws UnsupportedOperationException 154 * if this value is not a JSON object 155 */ 156 public JsonObject asObject() { 157 throw new UnsupportedOperationException("Not an object: " + toString()); 158 } 159 160 /** 161 * Returns this JSON value as {@link JsonArray}, assuming that this value represents a JSON array. If this is not the 162 * case, an exception is thrown. 163 * 164 * @return a JSONArray for this value 165 * @throws UnsupportedOperationException 166 * if this value is not a JSON array 167 */ 168 public JsonArray asArray() { 169 throw new UnsupportedOperationException("Not an array: " + toString()); 170 } 171 172 /** 173 * Returns this JSON value as an <code>int</code> value, assuming that this value represents a JSON number that can be 174 * interpreted as Java <code>int</code>. If this is not the case, an exception is thrown. 175 * <p> 176 * To be interpreted as Java <code>int</code>, the JSON number must neither contain an exponent nor a fraction part. 177 * Moreover, the number must be in the <code>Integer</code> range. 178 * </p> 179 * 180 * @return this value as <code>int</code> 181 * @throws UnsupportedOperationException 182 * if this value is not a JSON number 183 * @throws NumberFormatException 184 * if this JSON number can not be interpreted as <code>int</code> value 185 */ 186 public int asInt() { 187 throw new UnsupportedOperationException(NOT_A_NUMBER + toString()); 188 } 189 190 /** 191 * Returns this JSON value as a <code>long</code> value, assuming that this value represents a JSON number that can be 192 * interpreted as Java <code>long</code>. If this is not the case, an exception is thrown. 193 * <p> 194 * To be interpreted as Java <code>long</code>, the JSON number must neither contain an exponent nor a fraction part. 195 * Moreover, the number must be in the <code>Long</code> range. 196 * </p> 197 * 198 * @return this value as <code>long</code> 199 * @throws UnsupportedOperationException 200 * if this value is not a JSON number 201 * @throws NumberFormatException 202 * if this JSON number can not be interpreted as <code>long</code> value 203 */ 204 public long asLong() { 205 throw new UnsupportedOperationException(NOT_A_NUMBER + toString()); 206 } 207 208 /** 209 * Returns this JSON value as a <code>float</code> value, assuming that this value represents a JSON number. If this 210 * is not the case, an exception is thrown. 211 * <p> 212 * If the JSON number is out of the <code>Float</code> range, {@link Float#POSITIVE_INFINITY} or 213 * {@link Float#NEGATIVE_INFINITY} is returned. 214 * </p> 215 * 216 * @return this value as <code>float</code> 217 * @throws UnsupportedOperationException 218 * if this value is not a JSON number 219 */ 220 public float asFloat() { 221 throw new UnsupportedOperationException(NOT_A_NUMBER + toString()); 222 } 223 224 /** 225 * Returns this JSON value as a <code>double</code> value, assuming that this value represents a JSON number. If this 226 * is not the case, an exception is thrown. 227 * <p> 228 * If the JSON number is out of the <code>Double</code> range, {@link Double#POSITIVE_INFINITY} or 229 * {@link Double#NEGATIVE_INFINITY} is returned. 230 * </p> 231 * 232 * @return this value as <code>double</code> 233 * @throws UnsupportedOperationException 234 * if this value is not a JSON number 235 */ 236 public double asDouble() { 237 throw new UnsupportedOperationException(NOT_A_NUMBER + toString()); 238 } 239 240 /** 241 * Returns this JSON value as String, assuming that this value represents a JSON string. If this is not the case, an 242 * exception is thrown. 243 * 244 * @return the string represented by this value 245 * @throws UnsupportedOperationException 246 * if this value is not a JSON string 247 */ 248 public String asString() { 249 throw new UnsupportedOperationException(NOT_A_STRING + toString()); 250 } 251 252 /** 253 * Returns this JSON value as a <code>boolean</code> value, assuming that this value is either <code>true</code> or 254 * <code>false</code>. If this is not the case, an exception is thrown. 255 * 256 * @return this value as <code>boolean</code> 257 * @throws UnsupportedOperationException 258 * if this value is neither <code>true</code> or <code>false</code> 259 */ 260 public boolean asBoolean() { 261 throw new UnsupportedOperationException(NOT_A_BOOLEAN + toString()); 262 } 263 264 /** 265 * Writes the JSON representation of this value to the given writer in its minimal form, without any additional 266 * whitespace. 267 * <p> 268 * Writing performance can be improved by using a {@link java.io.BufferedWriter BufferedWriter}. 269 * </p> 270 * 271 * @param writer 272 * the writer to write this value to 273 * @throws IOException 274 * if an I/O error occurs in the writer 275 */ 276 public void writeTo(Writer writer) throws IOException { 277 writeTo(writer, WriterConfig.MINIMAL); 278 } 279 280 /** 281 * Writes the JSON representation of this value to the given writer using the given formatting. 282 * <p> 283 * Writing performance can be improved by using a {@link java.io.BufferedWriter BufferedWriter}. 284 * </p> 285 * 286 * @param writer 287 * the writer to write this value to 288 * @param config 289 * a configuration that controls the formatting or <code>null</code> for the minimal form 290 * @throws IOException 291 * if an I/O error occurs in the writer 292 */ 293 public void writeTo(Writer writer, WriterConfig config) throws IOException { 294 Objects.requireNonNull(writer, "writer is null"); 295 Objects.requireNonNull(config, "config is null"); 296 WritingBuffer buffer = new WritingBuffer(writer, 128); 297 write(config.createWriter(buffer)); 298 buffer.flush(); 299 } 300 301 /** 302 * Returns the JSON string for this value in its minimal form, without any additional whitespace. 303 * The result is guaranteed to be a valid input for the method {@link Json#parse(String)} and to 304 * create a value that is <em>equal</em> to this object. 305 * 306 * @return a JSON string that represents this value 307 */ 308 @Override 309 public String toString() { 310 return toString(WriterConfig.UNICODE); 311 } 312 313 /** 314 * Returns the JSON string for this value using the given formatting. 315 * 316 * @param config 317 * a configuration that controls the formatting or <code>null</code> for the minimal form 318 * @return a JSON string that represents this value 319 */ 320 public String toString(WriterConfig config) { 321 StringWriter writer = new StringWriter(); 322 try { 323 writeTo(writer, config); 324 } catch (IOException exception) { 325 // StringWriter does not throw IOExceptions 326 throw new RuntimeException(exception); 327 } 328 return writer.toString(); 329 } 330 331 /** 332 * Indicates whether some other object is "equal to" this one according to the contract specified in 333 * {@link Object#equals(Object)}. 334 * <p> 335 * Two JsonValues are considered equal if and only if they represent the same JSON text. As a consequence, two given 336 * JsonObjects may be different even though they contain the same set of names with the same values, but in a 337 * different order. 338 * </p> 339 * 340 * @param object 341 * the reference object with which to compare 342 * @return true if this object is the same as the object argument; false otherwise 343 */ 344 @Override 345 public boolean equals(Object object) { 346 return super.equals(object); 347 } 348 349 @Override 350 public int hashCode() { 351 return super.hashCode(); 352 } 353 354 abstract void write(JsonWriter writer) throws IOException; 355 356}