001/* Copyright 2016-2017 Clifton Labs
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 * http://www.apache.org/licenses/LICENSE-2.0
006 * Unless required by applicable law or agreed to in writing, software
007 * distributed under the License is distributed on an "AS IS" BASIS,
008 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
009 * See the License for the specific language governing permissions and
010 * limitations under the License. */
011package org.json.simple;
012
013import java.io.IOException;
014import java.io.StringWriter;
015import java.io.Writer;
016import java.math.BigDecimal;
017import java.util.Collection;
018import java.util.HashMap;
019import java.util.HashSet;
020import java.util.Iterator;
021import java.util.Map;
022import java.util.NoSuchElementException;
023import java.util.Set;
024
025/** JsonObject is a common non-thread safe data format for string to data mappings. The contents of a JsonObject are
026 * only validated as JSON values on serialization. Meaning all values added to a JsonObject must be recognized by the
027 * Jsoner for it to be a true 'JsonObject', so it is really a JsonableHashMap that will serialize to a JsonObject if all of
028 * its contents are valid JSON.
029 * @see Jsoner
030 * @since 2.0.0 */
031public class JsonObject extends HashMap<String, Object> implements Jsonable{
032        /** The serialization version this class is compatible
033         * with. This value doesn't need to be incremented if and only if the only changes to occur were updating comments,
034         * updating javadocs, adding new
035         * fields to the class, changing the fields from static to non-static, or changing the fields from transient to non
036         * transient. All other changes require this number be incremented. */
037        private static final long serialVersionUID = 2L;
038
039        /** Instantiates an empty JsonObject. */
040        public JsonObject(){
041                super();
042        }
043
044        /** Instantiate a new JsonObject by accepting a map's entries, which could lead to de/serialization issues of the
045         * resulting JsonObject since the entry values aren't validated as JSON values.
046         * @param map represents the mappings to produce the JsonObject with. */
047        public JsonObject(final Map<String, ?> map){
048                super(map);
049        }
050        
051        /** Ensures the given keys are present.
052         * @param keys represents the keys that must be present.
053         * @throws NoSuchElementException if any of the given keys are missing.
054         * @since 2.3.0 to ensure critical keys are in the JsonObject. */
055        public void requireKeys(final JsonKey... keys){
056                /* Track all of the missing keys. */
057                final Set<JsonKey> missing = new HashSet<>();
058                for(final JsonKey k : keys){
059                        if(!this.containsKey(k.getKey())){
060                                missing.add(k);
061                        }
062                }
063                if(!missing.isEmpty()){
064                        /* Report any missing keys in the exception. */
065                        final StringBuilder sb = new StringBuilder();
066                        for(final JsonKey k : missing){
067                                sb.append(k.getKey()).append(", ");
068                        }
069                        sb.setLength(sb.length() - 2);
070                        final String s = missing.size() > 1 ? "s" : "";
071                        throw new NoSuchElementException("A JsonObject is missing required key" + s + ": " + sb.toString());
072                }
073        }
074
075        /** A convenience method that assumes there is a BigDecimal, Number, or String at the given key. If a Number is
076         * there its Number#toString() is used to construct a new BigDecimal(String). If a String is there it is used to
077         * construct a new BigDecimal(String).
078         * @param key representing where the value ought to be paired with.
079         * @return a BigDecimal representing the value paired with the key.
080         * @throws ClassCastException if the value didn't match the assumed return type.
081         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
082         *         represents the double or float Infinity or NaN.
083         * @see BigDecimal
084         * @see Number#toString()
085         * @see JsonKey
086         * @since 2.3.0 to utilize JsonKey */
087        public BigDecimal getBigDecimal(final JsonKey key){
088                Object returnable = this.get(key.getKey());
089                if(returnable instanceof BigDecimal){
090                        /* Success there was a BigDecimal or it defaulted. */
091                }else if(returnable instanceof Number){
092                        /* A number can be used to construct a BigDecimal */
093                        returnable = new BigDecimal(returnable.toString());
094                }else if(returnable instanceof String){
095                        /* A number can be used to construct a BigDecimal */
096                        returnable = new BigDecimal((String)returnable);
097                }
098                return (BigDecimal)returnable;
099        }
100
101        /** A convenience method that assumes there is a BigDecimal, Number, or String at the given key. If a Number is
102         * there its Number#toString() is used to construct a new BigDecimal(String). If a String is there it is used to
103         * construct a new BigDecimal(String).
104         * @param key representing where the value ought to be stored at.
105         * @return the value stored at the key.
106         * @throws ClassCastException if the value didn't match the assumed return type.
107         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
108         *         represents the double or float Infinity or NaN.
109         * @see BigDecimal
110         * @see Number#toString()
111         * @deprecated 2.3.0 in favor of {@link #getBigDecimal(JsonKey)} */
112        @Deprecated
113        public BigDecimal getBigDecimal(final String key){
114                Object returnable = this.get(key);
115                if(returnable instanceof BigDecimal){
116                        /* Success there was a BigDecimal or it defaulted. */
117                }else if(returnable instanceof Number){
118                        /* A number can be used to construct a BigDecimal */
119                        returnable = new BigDecimal(returnable.toString());
120                }else if(returnable instanceof String){
121                        /* A number can be used to construct a BigDecimal */
122                        returnable = new BigDecimal((String)returnable);
123                }
124                return (BigDecimal)returnable;
125        }
126
127        /** A convenience method that assumes there is a BigDecimal, Number, or String at the given key. If a Number is
128         * there its Number#toString() is used to construct a new BigDecimal(String). If a String is there it is used to
129         * construct a new BigDecimal(String).
130         * @param key representing where the value ought to be paired with.
131         * @return a BigDecimal representing the value paired with the key or JsonKey#getValue() if the key isn't present.
132         * @throws ClassCastException if the value didn't match the assumed return type.
133         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
134         *         represents the double or float Infinity or NaN.
135         * @see BigDecimal
136         * @see Number#toString()
137         * @see JsonKey
138         * @since 2.3.0 to utilize JsonKey */
139        public BigDecimal getBigDecimalOrDefault(final JsonKey key){
140                Object returnable;
141                if(this.containsKey(key.getKey())){
142                        returnable = this.get(key.getKey());
143                }else{
144                        returnable = key.getValue();
145                }
146                if(returnable instanceof BigDecimal){
147                        /* Success there was a BigDecimal or it defaulted. */
148                }else if(returnable instanceof Number){
149                        /* A number can be used to construct a BigDecimal */
150                        returnable = new BigDecimal(returnable.toString());
151                }else if(returnable instanceof String){
152                        /* A String can be used to construct a BigDecimal */
153                        returnable = new BigDecimal((String)returnable);
154                }
155                return (BigDecimal)returnable;
156        }
157
158        /** A convenience method that assumes there is a BigDecimal, Number, or String at the given key. If a Number is
159         * there its Number#toString() is used to construct a new BigDecimal(String). If a String is there it is used to
160         * construct a new BigDecimal(String).
161         * @param key representing where the value ought to be stored at.
162         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
163         * @return the value stored at the key or the default provided if the key doesn't exist.
164         * @throws ClassCastException if there was a value but didn't match the assumed return types.
165         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
166         *         represents the double or float Infinity or NaN.
167         * @see BigDecimal
168         * @see Number#toString()
169         * @deprecated 2.3.0 in favor of {@link #getBigDecimalOrDefault(JsonKey)} */
170        @Deprecated
171        public BigDecimal getBigDecimalOrDefault(final String key, final BigDecimal defaultValue){
172                Object returnable;
173                if(this.containsKey(key)){
174                        returnable = this.get(key);
175                }else{
176                        return defaultValue;
177                }
178                if(returnable instanceof BigDecimal){
179                        /* Success there was a BigDecimal or it defaulted. */
180                }else if(returnable instanceof Number){
181                        /* A number can be used to construct a BigDecimal */
182                        returnable = new BigDecimal(returnable.toString());
183                }else if(returnable instanceof String){
184                        /* A String can be used to construct a BigDecimal */
185                        returnable = new BigDecimal((String)returnable);
186                }
187                return (BigDecimal)returnable;
188        }
189
190        /** A convenience method that assumes there is a Boolean or String value at the given key.
191         * @param key representing where the value ought to be paired with.
192         * @return a Boolean representing the value paired with the key.
193         * @throws ClassCastException if the value didn't match the assumed return type.
194         * @see JsonKey
195         * @since 2.3.0 to utilize JsonKey */
196        public Boolean getBoolean(final JsonKey key){
197                Object returnable = this.get(key.getKey());
198                if(returnable instanceof String){
199                        returnable = Boolean.valueOf((String)returnable);
200                }
201                return (Boolean)returnable;
202        }
203
204        /** A convenience method that assumes there is a Boolean or String value at the given key.
205         * @param key representing where the value ought to be stored at.
206         * @return the value stored at the key.
207         * @throws ClassCastException if the value didn't match the assumed return type.
208         * @deprecated 2.3.0 in favor of {@link #getBoolean(JsonKey)} */
209        @Deprecated
210        public Boolean getBoolean(final String key){
211                Object returnable = this.get(key);
212                if(returnable instanceof String){
213                        returnable = Boolean.valueOf((String)returnable);
214                }
215                return (Boolean)returnable;
216        }
217
218        /** A convenience method that assumes there is a Boolean or String value at the given key.
219         * @param key representing where the value ought to be paired with.
220         * @return a Boolean representing the value paired with the key or JsonKey#getValue() if the key isn't present.
221         * @throws ClassCastException if the value didn't match the assumed return type.
222         * @see JsonKey
223         * @since 2.3.0 to utilize JsonKey */
224        public Boolean getBooleanOrDefault(final JsonKey key){
225                Object returnable;
226                if(this.containsKey(key.getKey())){
227                        returnable = this.get(key.getKey());
228                }else{
229                        returnable = key.getValue();
230                }
231                if(returnable instanceof String){
232                        returnable = Boolean.valueOf((String)returnable);
233                }
234                return (Boolean)returnable;
235        }
236
237        /** A convenience method that assumes there is a Boolean or String value at the given key.
238         * @param key representing where the value ought to be stored at.
239         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
240         * @return the value stored at the key or the default provided if the key doesn't exist.
241         * @throws ClassCastException if there was a value but didn't match the assumed return type.
242         * @deprecated 2.3.0 in favor of {@link #getBooleanOrDefault(JsonKey)} */
243        @Deprecated
244        public Boolean getBooleanOrDefault(final String key, final boolean defaultValue){
245                Object returnable;
246                if(this.containsKey(key)){
247                        returnable = this.get(key);
248                }else{
249                        return defaultValue;
250                }
251                if(returnable instanceof String){
252                        returnable = Boolean.valueOf((String)returnable);
253                }
254                return (Boolean)returnable;
255        }
256
257        /** A convenience method that assumes there is a Number or String value at the given key.
258         * @param key representing where the value ought to be paired with.
259         * @return a Byte representing the value paired with the key (which may involve rounding or truncation).
260         * @throws ClassCastException if the value didn't match the assumed return type.
261         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
262         *         represents the double or float Infinity or NaN.
263         * @see Number#byteValue()
264         * @see JsonKey
265         * @since 2.3.0 to utilize JsonKey */
266        public Byte getByte(final JsonKey key){
267                Object returnable = this.get(key.getKey());
268                if(returnable == null){
269                        return null;
270                }
271                if(returnable instanceof String){
272                        /* A String can be used to construct a BigDecimal. */
273                        returnable = new BigDecimal((String)returnable);
274                }
275                return ((Number)returnable).byteValue();
276        }
277
278        /** A convenience method that assumes there is a Number or String value at the given key.
279         * @param key representing where the value ought to be stored at.
280         * @return the value stored at the key (which may involve rounding or truncation).
281         * @throws ClassCastException if the value didn't match the assumed return type.
282         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
283         *         represents the double or float Infinity or NaN.
284         * @see Number#byteValue()
285         * @deprecated 2.3.0 in favor of {@link #getByte(JsonKey)} */
286        @Deprecated
287        public Byte getByte(final String key){
288                Object returnable = this.get(key);
289                if(returnable == null){
290                        return null;
291                }
292                if(returnable instanceof String){
293                        /* A String can be used to construct a BigDecimal. */
294                        returnable = new BigDecimal((String)returnable);
295                }
296                return ((Number)returnable).byteValue();
297        }
298
299        /** A convenience method that assumes there is a Number or String value at the given key.
300         * @param key representing where the value ought to be paired with.
301         * @return a Byte representing the value paired with the key or JsonKey#getValue() if the key isn't present (which
302         *         may involve rounding or truncation).
303         * @throws ClassCastException if the value didn't match the assumed return type.
304         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
305         *         represents the double or float Infinity or NaN.
306         * @see Number#byteValue()
307         * @see JsonKey
308         * @since 2.3.0 to utilize JsonKey */
309        public Byte getByteOrDefault(final JsonKey key){
310                Object returnable;
311                if(this.containsKey(key.getKey())){
312                        returnable = this.get(key.getKey());
313                }else{
314                        returnable = key.getValue();
315                }
316                if(returnable == null){
317                        return null;
318                }
319                if(returnable instanceof String){
320                        /* A String can be used to construct a BigDecimal. */
321                        returnable = new BigDecimal((String)returnable);
322                }
323                return ((Number)returnable).byteValue();
324        }
325
326        /** A convenience method that assumes there is a Number or String value at the given key.
327         * @param key representing where the value ought to be stored at.
328         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
329         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
330         *         doesn't exist.
331         * @throws ClassCastException if there was a value but didn't match the assumed return type.
332         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
333         *         represents the double or float Infinity or NaN.
334         * @see Number#byteValue()
335         * @deprecated 2.3.0 in favor of {@link #getByteOrDefault(JsonKey)} */
336        @Deprecated
337        public Byte getByteOrDefault(final String key, final byte defaultValue){
338                Object returnable;
339                if(this.containsKey(key)){
340                        returnable = this.get(key);
341                }else{
342                        return defaultValue;
343                }
344                if(returnable == null){
345                        return null;
346                }
347                if(returnable instanceof String){
348                        /* A String can be used to construct a BigDecimal. */
349                        returnable = new BigDecimal((String)returnable);
350                }
351                return ((Number)returnable).byteValue();
352        }
353
354        /** A convenience method that assumes there is a Collection at the given key.
355         * @param <T> the kind of collection to expect at the key. Note unless manually added, collection values will be a
356         *        JsonArray.
357         * @param key representing where the value ought to be paired with.
358         * @return a Collection representing the value paired with the key.
359         * @throws ClassCastException if the value didn't match the assumed return type.
360         * @see JsonKey
361         * @since 2.3.0 to utilize JsonKey */
362        @SuppressWarnings("unchecked")
363        public <T extends Collection<?>> T getCollection(final JsonKey key){
364                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
365                 * work. */
366                return (T)this.get(key.getKey());
367        }
368
369        /** A convenience method that assumes there is a Collection at the given key.
370         * @param <T> the kind of collection to expect at the key. Note unless manually added, collection values will be a
371         *        JsonArray.
372         * @param key representing where the value ought to be stored at.
373         * @return the value stored at the key.
374         * @throws ClassCastException if the value didn't match the assumed return type.
375         * @deprecated 2.3.0 in favor of {@link #getCollection(JsonKey)} */
376        @Deprecated
377        @SuppressWarnings("unchecked")
378        public <T extends Collection<?>> T getCollection(final String key){
379                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
380                 * work. */
381                return (T)this.get(key);
382        }
383
384        /** A convenience method that assumes there is a Collection at the given key.
385         * @param <T> the kind of collection to expect at the key. Note unless manually added, collection values will be a
386         *        JsonArray.
387         * @param key representing where the value ought to be paired with.
388         * @return a Collection representing the value paired with the key or JsonKey#getValue() if the key isn't present..
389         * @throws ClassCastException if the value didn't match the assumed return type.
390         * @see JsonKey
391         * @since 2.3.0 to utilize JsonKey */
392        @SuppressWarnings("unchecked")
393        public <T extends Collection<?>> T getCollectionOrDefault(final JsonKey key){
394                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
395                 * work. */
396                Object returnable;
397                if(this.containsKey(key.getKey())){
398                        returnable = this.get(key.getKey());
399                }else{
400                        returnable = key.getValue();
401                }
402                return (T)returnable;
403        }
404
405        /** A convenience method that assumes there is a Collection at the given key.
406         * @param <T> the kind of collection to expect at the key. Note unless manually added, collection values will be a
407         *        JsonArray.
408         * @param key representing where the value ought to be stored at.
409         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
410         * @return the value stored at the key or the default provided if the key doesn't exist.
411         * @throws ClassCastException if there was a value but didn't match the assumed return type.
412         * @deprecated 2.3.0 in favor of {@link #getCollectionOrDefault(JsonKey)} */
413        @Deprecated
414        @SuppressWarnings("unchecked")
415        public <T extends Collection<?>> T getCollectionOrDefault(final String key, final T defaultValue){
416                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
417                 * work. */
418                Object returnable;
419                if(this.containsKey(key)){
420                        returnable = this.get(key);
421                }else{
422                        return defaultValue;
423                }
424                return (T)returnable;
425        }
426
427        /** A convenience method that assumes there is a Number or String value at the given key.
428         * @param key representing where the value ought to be paired with.
429         * @return a Double representing the value paired with the key (which may involve rounding or truncation).
430         * @throws ClassCastException if the value didn't match the assumed return type.
431         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
432         *         represents the double or float Infinity or NaN.
433         * @see Number#doubleValue()
434         * @see JsonKey
435         * @since 2.3.0 to utilize JsonKey */
436        public Double getDouble(final JsonKey key){
437                Object returnable = this.get(key.getKey());
438                if(returnable == null){
439                        return null;
440                }
441                if(returnable instanceof String){
442                        /* A String can be used to construct a BigDecimal. */
443                        returnable = new BigDecimal((String)returnable);
444                }
445                return ((Number)returnable).doubleValue();
446        }
447
448        /** A convenience method that assumes there is a Number or String value at the given key.
449         * @param key representing where the value ought to be stored at.
450         * @return the value stored at the key (which may involve rounding or truncation).
451         * @throws ClassCastException if the value didn't match the assumed return type.
452         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
453         *         represents the double or float Infinity or NaN.
454         * @see Number#doubleValue()
455         * @deprecated 2.3.0 in favor of {@link #getDouble(JsonKey)} */
456        @Deprecated
457        public Double getDouble(final String key){
458                Object returnable = this.get(key);
459                if(returnable == null){
460                        return null;
461                }
462                if(returnable instanceof String){
463                        /* A String can be used to construct a BigDecimal. */
464                        returnable = new BigDecimal((String)returnable);
465                }
466                return ((Number)returnable).doubleValue();
467        }
468
469        /** A convenience method that assumes there is a Number or String value at the given key.
470         * @param key representing where the value ought to be paired with.
471         * @return a Double representing the value paired with the key or JsonKey#getValue() if the key isn't present (which
472         *         may involve rounding or truncation).
473         * @throws ClassCastException if the value didn't match the assumed return type.
474         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
475         *         represents the double or float Infinity or NaN.
476         * @see Number#doubleValue()
477         * @see JsonKey
478         * @since 2.3.0 to utilize JsonKey */
479        public Double getDoubleOrDefault(final JsonKey key){
480                Object returnable;
481                if(this.containsKey(key.getKey())){
482                        returnable = this.get(key.getKey());
483                }else{
484                        returnable = key.getValue();
485                }
486                if(returnable == null){
487                        return null;
488                }
489                if(returnable instanceof String){
490                        /* A String can be used to construct a BigDecimal. */
491                        returnable = new BigDecimal((String)returnable);
492                }
493                return ((Number)returnable).doubleValue();
494        }
495
496        /** A convenience method that assumes there is a Number or String value at the given key.
497         * @param key representing where the value ought to be stored at.
498         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
499         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
500         *         doesn't exist.
501         * @throws ClassCastException if there was a value but didn't match the assumed return type.
502         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
503         *         represents the double or float Infinity or NaN.
504         * @see Number#doubleValue()
505         * @deprecated 2.3.0 in favor of {@link #getDoubleOrDefault(JsonKey)} */
506        @Deprecated
507        public Double getDoubleOrDefault(final String key, final double defaultValue){
508                Object returnable;
509                if(this.containsKey(key)){
510                        returnable = this.get(key);
511                }else{
512                        return defaultValue;
513                }
514                if(returnable == null){
515                        return null;
516                }
517                if(returnable instanceof String){
518                        /* A String can be used to construct a BigDecimal. */
519                        returnable = new BigDecimal((String)returnable);
520                }
521                return ((Number)returnable).doubleValue();
522        }
523
524        /** A convenience method that assumes there is a String value at the given key representing a fully qualified name
525         * in dot notation of an enum.
526         * @param key representing where the value ought to be paired with.
527         * @param <T> the Enum type the value at the key is expected to belong to.
528         * @return an Enum representing the value paired with the key.
529         * @throws ClassNotFoundException if the value was a String but the declaring enum type couldn't be determined with
530         *         it.
531         * @throws ClassCastException if the element at the index was not a String or if the fully qualified enum name is of
532         *         the wrong type.
533         * @throws IllegalArgumentException if an enum type was determined but it doesn't define an enum with the determined
534         *         name.
535         * @see Enum#valueOf(Class, String)
536         * @see JsonKey
537         * @since 2.3.0 to utilize JsonKey
538         * @deprecated 2.3.0 Jsoner deprecated automatically serializing enums as Strings. */
539        @Deprecated
540        @SuppressWarnings("unchecked")
541        public <T extends Enum<T>> T getEnum(final JsonKey key) throws ClassNotFoundException{
542                /* Supressing the unchecked warning because the returnType is dynamically identified and could lead to a
543                 * ClassCastException when returnType is cast to Class<T>, which is acceptable by the method's contract. */
544                T returnable;
545                final String value;
546                final String[] splitValues;
547                final int numberOfSplitValues;
548                final StringBuilder returnTypeName;
549                final StringBuilder enumName;
550                final Class<T> returnType;
551                /* Make sure the value at the key is a String. */
552                value = this.getString(key);
553                if(value == null){
554                        return null;
555                }
556                /* Get the package, class, and enum names. */
557                splitValues = value.split("\\.");
558                numberOfSplitValues = splitValues.length;
559                returnTypeName = new StringBuilder();
560                enumName = new StringBuilder();
561                for(int i = 0; i < numberOfSplitValues; i++){
562                        if(i == (numberOfSplitValues - 1)){
563                                /* If it is the last split value then it should be the name of the Enum since dots are not allowed
564                                 * in enum names. */
565                                enumName.append(splitValues[i]);
566                        }else if(i == (numberOfSplitValues - 2)){
567                                /* If it is the penultimate split value then it should be the end of the package/enum type and not
568                                 * need a dot appended to it. */
569                                returnTypeName.append(splitValues[i]);
570                        }else{
571                                /* Must be part of the package/enum type and will need a dot appended to it since they got removed
572                                 * in the split. */
573                                returnTypeName.append(splitValues[i]);
574                                returnTypeName.append(".");
575                        }
576                }
577                /* Use the package/class and enum names to get the Enum<T>. */
578                returnType = (Class<T>)Class.forName(returnTypeName.toString());
579                returnable = Enum.valueOf(returnType, enumName.toString());
580                return returnable;
581        }
582
583        /** A convenience method that assumes there is a String value at the given key representing a fully qualified name
584         * in dot notation of an enum.
585         * @param key representing where the value ought to be stored at.
586         * @param <T> the Enum type the value at the key is expected to belong to.
587         * @return the enum based on the string found at the key, or null if the value paired with the provided key is null.
588         * @throws ClassNotFoundException if the value was a String but the declaring enum type couldn't be determined with
589         *         it.
590         * @throws ClassCastException if the element at the index was not a String or if the fully qualified enum name is of
591         *         the wrong type.
592         * @throws IllegalArgumentException if an enum type was determined but it doesn't define an enum with the determined
593         *         name.
594         * @see Enum#valueOf(Class, String)
595         * @deprecated 2.3.0 in favor of {@link #getEnum(JsonKey)} */
596        @Deprecated
597        @SuppressWarnings("unchecked")
598        public <T extends Enum<T>> T getEnum(final String key) throws ClassNotFoundException{
599                /* Supressing the unchecked warning because the returnType is dynamically identified and could lead to a
600                 * ClassCastException when returnType is cast to Class<T>, which is expected by the method's contract. */
601                T returnable;
602                final String value;
603                final String[] splitValues;
604                final int numberOfSplitValues;
605                final StringBuilder returnTypeName;
606                final StringBuilder enumName;
607                final Class<T> returnType;
608                /* Make sure the value at the key is a String. */
609                value = this.getStringOrDefault(key, "");
610                if(value == null){
611                        return null;
612                }
613                /* Get the package, class, and enum names. */
614                splitValues = value.split("\\.");
615                numberOfSplitValues = splitValues.length;
616                returnTypeName = new StringBuilder();
617                enumName = new StringBuilder();
618                for(int i = 0; i < numberOfSplitValues; i++){
619                        if(i == (numberOfSplitValues - 1)){
620                                /* If it is the last split value then it should be the name of the Enum since dots are not allowed
621                                 * in enum names. */
622                                enumName.append(splitValues[i]);
623                        }else if(i == (numberOfSplitValues - 2)){
624                                /* If it is the penultimate split value then it should be the end of the package/enum type and not
625                                 * need a dot appended to it. */
626                                returnTypeName.append(splitValues[i]);
627                        }else{
628                                /* Must be part of the package/enum type and will need a dot appended to it since they got removed
629                                 * in the split. */
630                                returnTypeName.append(splitValues[i]);
631                                returnTypeName.append(".");
632                        }
633                }
634                /* Use the package/class and enum names to get the Enum<T>. */
635                returnType = (Class<T>)Class.forName(returnTypeName.toString());
636                returnable = Enum.valueOf(returnType, enumName.toString());
637                return returnable;
638        }
639
640        /** A convenience method that assumes there is a String value at the given key representing a fully qualified name
641         * in dot notation of an enum.
642         * @param key representing where the value ought to be paired with.
643         * @param <T> the Enum type the value at the key is expected to belong to.
644         * @return an Enum representing the value paired with the key or JsonKey#getValue() if the key isn't present.
645         * @throws ClassNotFoundException if the value was a String but the declaring enum type couldn't be determined with
646         *         it.
647         * @throws ClassCastException if the element at the index was not a String or if the fully qualified enum name is of
648         *         the wrong type.
649         * @throws IllegalArgumentException if an enum type was determined but it doesn't define an enum with the determined
650         *         name.
651         * @see Enum#valueOf(Class, String)
652         * @see JsonKey
653         * @since 2.3.0 to utilize JsonKey
654         * @deprecated 2.3.0 Jsoner deprecated automatically serializing enums as Strings. */
655        @Deprecated
656        @SuppressWarnings("unchecked")
657        public <T extends Enum<T>> T getEnumOrDefault(final JsonKey key) throws ClassNotFoundException{
658                /* Supressing the unchecked warning because the returnType is dynamically identified and could lead to a
659                 * ClassCastException when returnType is cast to Class<T>, which is acceptable by the method's contract. */
660                T returnable;
661                final String value;
662                final String[] splitValues;
663                final int numberOfSplitValues;
664                final StringBuilder returnTypeName;
665                final StringBuilder enumName;
666                final Class<T> returnType;
667                /* Check to make sure the key is there. */
668                if(this.containsKey(key)){
669                        /* Make sure the value at the key is a String. */
670                        value = this.getStringOrDefault(key.getKey(), "");
671                        if(value == null){
672                                return null;
673                        }
674                        /* Get the package, class, and enum names. */
675                        splitValues = value.split("\\.");
676                        numberOfSplitValues = splitValues.length;
677                        returnTypeName = new StringBuilder();
678                        enumName = new StringBuilder();
679                        for(int i = 0; i < numberOfSplitValues; i++){
680                                if(i == (numberOfSplitValues - 1)){
681                                        /* If it is the last split value then it should be the name of the Enum since dots are not allowed
682                                         * in enum names. */
683                                        enumName.append(splitValues[i]);
684                                }else if(i == (numberOfSplitValues - 2)){
685                                        /* If it is the penultimate split value then it should be the end of the package/enum type and not
686                                         * need a dot appended to it. */
687                                        returnTypeName.append(splitValues[i]);
688                                }else{
689                                        /* Must be part of the package/enum type and will need a dot appended to it since they got removed
690                                         * in the split. */
691                                        returnTypeName.append(splitValues[i]);
692                                        returnTypeName.append(".");
693                                }
694                        }
695                        /* Use the package/class and enum names to get the Enum<T>. */
696                        returnType = (Class<T>)Class.forName(returnTypeName.toString());
697                        returnable = Enum.valueOf(returnType, enumName.toString());
698                }else{
699                        /* It wasn't there and according to the method's contract we return the default value. */
700                        returnable = (T)key.getValue();
701                }
702                return returnable;
703        }
704
705        /** A convenience method that assumes there is a String value at the given key representing a fully qualified name
706         * in dot notation of an enum.
707         * @param key representing where the value ought to be stored at.
708         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
709         * @param <T> the Enum type the value at the key is expected to belong to.
710         * @return the enum based on the string found at the key, or the defaultValue provided if the key doesn't exist, or
711         *         null if the value paired with provided key is null.
712         * @throws ClassNotFoundException if the value was a String but the declaring enum type couldn't be determined with
713         *         it.
714         * @throws ClassCastException if the element at the index was not a String or if the fully qualified enum name is of
715         *         the wrong type.
716         * @throws IllegalArgumentException if an enum type was determined but it doesn't define an enum with the determined
717         *         name.
718         * @see Enum#valueOf(Class, String)
719         * @deprecated 2.3.0 in favor of {@link #getEnumOrDefault(JsonKey)} */
720        @Deprecated
721        @SuppressWarnings("unchecked")
722        public <T extends Enum<T>> T getEnumOrDefault(final String key, final T defaultValue) throws ClassNotFoundException{
723                /* Supressing the unchecked warning because the returnType is dynamically identified and could lead to a
724                 * ClassCastException when returnType is cast to Class<T>, which is expected by the method's contract. */
725                T returnable;
726                final String value;
727                final String[] splitValues;
728                final int numberOfSplitValues;
729                final StringBuilder returnTypeName;
730                final StringBuilder enumName;
731                final Class<T> returnType;
732                /* Check to make sure the key wasn't actually there and wasn't coincidentally the defaulted String as its
733                 * value. */
734                if(this.containsKey(key)){
735                        /* Make sure the value at the key is a String. */
736                        value = this.getStringOrDefault(key, "");
737                        if(value == null){
738                                return null;
739                        }
740                        /* Get the package, class, and enum names. */
741                        splitValues = value.split("\\.");
742                        numberOfSplitValues = splitValues.length;
743                        returnTypeName = new StringBuilder();
744                        enumName = new StringBuilder();
745                        for(int i = 0; i < numberOfSplitValues; i++){
746                                if(i == (numberOfSplitValues - 1)){
747                                        /* If it is the last split value then it should be the name of the Enum since dots are not allowed
748                                         * in enum names. */
749                                        enumName.append(splitValues[i]);
750                                }else if(i == (numberOfSplitValues - 2)){
751                                        /* If it is the penultimate split value then it should be the end of the package/enum type and not
752                                         * need a dot appended to it. */
753                                        returnTypeName.append(splitValues[i]);
754                                }else{
755                                        /* Must be part of the package/enum type and will need a dot appended to it since they got removed
756                                         * in the split. */
757                                        returnTypeName.append(splitValues[i]);
758                                        returnTypeName.append(".");
759                                }
760                        }
761                        /* Use the package/class and enum names to get the Enum<T>. */
762                        returnType = (Class<T>)Class.forName(returnTypeName.toString());
763                        returnable = Enum.valueOf(returnType, enumName.toString());
764                }else{
765                        /* It wasn't there and according to the method's contract we return the default value. */
766                        return defaultValue;
767                }
768                return returnable;
769        }
770
771        /** A convenience method that assumes there is a Number or String value at the given key.
772         * @param key representing where the value ought to be paired with.
773         * @return a Float representing the value paired with the key (which may involve rounding or truncation).
774         * @throws ClassCastException if the value didn't match the assumed return type.
775         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
776         *         represents the double or float Infinity or NaN.
777         * @see Number#floatValue()
778         * @see JsonKey
779         * @since 2.3.0 to utilize JsonKey */
780        public Float getFloat(final JsonKey key){
781                Object returnable = this.get(key.getKey());
782                if(returnable == null){
783                        return null;
784                }
785                if(returnable instanceof String){
786                        /* A String can be used to construct a BigDecimal. */
787                        returnable = new BigDecimal((String)returnable);
788                }
789                return ((Number)returnable).floatValue();
790        }
791
792        /** A convenience method that assumes there is a Number or String value at the given key.
793         * @param key representing where the value ought to be stored at.
794         * @return the value stored at the key (which may involve rounding or truncation).
795         * @throws ClassCastException if the value didn't match the assumed return type.
796         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
797         *         represents the double or float Infinity or NaN.
798         * @see Number#floatValue()
799         * @deprecated 2.3.0 in favor of {@link #getFloat(JsonKey)} */
800        @Deprecated
801        public Float getFloat(final String key){
802                Object returnable = this.get(key);
803                if(returnable == null){
804                        return null;
805                }
806                if(returnable instanceof String){
807                        /* A String can be used to construct a BigDecimal. */
808                        returnable = new BigDecimal((String)returnable);
809                }
810                return ((Number)returnable).floatValue();
811        }
812
813        /** A convenience method that assumes there is a Number or String value at the given key.
814         * @param key representing where the value ought to be paired with.
815         * @return a Float representing the value paired with the key or JsonKey#getValue() if the key isn't present (which
816         *         may involve rounding or truncation).
817         * @throws ClassCastException if the value didn't match the assumed return type.
818         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
819         *         represents the double or float Infinity or NaN.
820         * @see Number#floatValue()
821         * @see JsonKey
822         * @since 2.3.0 to utilize JsonKey */
823        public Float getFloatOrDefault(final JsonKey key){
824                Object returnable;
825                if(this.containsKey(key.getKey())){
826                        returnable = this.get(key.getKey());
827                }else{
828                        returnable = key.getValue();
829                }
830                if(returnable == null){
831                        return null;
832                }
833                if(returnable instanceof String){
834                        /* A String can be used to construct a BigDecimal. */
835                        returnable = new BigDecimal((String)returnable);
836                }
837                return ((Number)returnable).floatValue();
838        }
839
840        /** A convenience method that assumes there is a Number or String value at the given key.
841         * @param key representing where the value ought to be stored at.
842         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
843         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
844         *         doesn't exist.
845         * @throws ClassCastException if there was a value but didn't match the assumed return type.
846         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
847         *         represents the double or float Infinity or NaN.
848         * @see Number#floatValue()
849         * @deprecated 2.3.0 in favor of {@link #getFloatOrDefault(JsonKey)} */
850        @Deprecated
851        public Float getFloatOrDefault(final String key, final float defaultValue){
852                Object returnable;
853                if(this.containsKey(key)){
854                        returnable = this.get(key);
855                }else{
856                        return defaultValue;
857                }
858                if(returnable == null){
859                        return null;
860                }
861                if(returnable instanceof String){
862                        /* A String can be used to construct a BigDecimal. */
863                        returnable = new BigDecimal((String)returnable);
864                }
865                return ((Number)returnable).floatValue();
866        }
867
868        /** A convenience method that assumes there is a Number or String value at the given key.
869         * @param key representing where the value ought to be paired with.
870         * @return an Integer representing the value paired with the key (which may involve rounding or truncation).
871         * @throws ClassCastException if the value didn't match the assumed return type.
872         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
873         *         represents the double or float Infinity or NaN.
874         * @see Number#intValue()
875         * @see JsonKey
876         * @since 2.3.0 to utilize JsonKey */
877        public Integer getInteger(final JsonKey key){
878                Object returnable = this.get(key.getKey());
879                if(returnable == null){
880                        return null;
881                }
882                if(returnable instanceof String){
883                        /* A String can be used to construct a BigDecimal. */
884                        returnable = new BigDecimal((String)returnable);
885                }
886                return ((Number)returnable).intValue();
887        }
888
889        /** A convenience method that assumes there is a Number or String value at the given key.
890         * @param key representing where the value ought to be stored at.
891         * @return the value stored at the key (which may involve rounding or truncation).
892         * @throws ClassCastException if the value didn't match the assumed return type.
893         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
894         *         represents the double or float Infinity or NaN.
895         * @see Number#intValue()
896         * @deprecated 2.3.0 in favor of {@link #getInteger(JsonKey)} */
897        @Deprecated
898        public Integer getInteger(final String key){
899                Object returnable = this.get(key);
900                if(returnable == null){
901                        return null;
902                }
903                if(returnable instanceof String){
904                        /* A String can be used to construct a BigDecimal. */
905                        returnable = new BigDecimal((String)returnable);
906                }
907                return ((Number)returnable).intValue();
908        }
909
910        /** A convenience method that assumes there is a Number or String value at the given key.
911         * @param key representing where the value ought to be paired with.
912         * @return an Integer representing the value paired with the key or JsonKey#getValue() if the key isn't present
913         *         (which may involve rounding or truncation).
914         * @throws ClassCastException if the value didn't match the assumed return type.
915         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
916         *         represents the double or float Infinity or NaN.
917         * @see Number#intValue()
918         * @see JsonKey
919         * @since 2.3.0 to utilize JsonKey */
920        public Integer getIntegerOrDefault(final JsonKey key){
921                Object returnable;
922                if(this.containsKey(key.getKey())){
923                        returnable = this.get(key.getKey());
924                }else{
925                        returnable = key.getValue();
926                }
927                if(returnable == null){
928                        return null;
929                }
930                if(returnable instanceof String){
931                        /* A String can be used to construct a BigDecimal. */
932                        returnable = new BigDecimal((String)returnable);
933                }
934                return ((Number)returnable).intValue();
935        }
936
937        /** A convenience method that assumes there is a Number or String value at the given key.
938         * @param key representing where the value ought to be stored at.
939         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
940         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
941         *         doesn't exist.
942         * @throws ClassCastException if there was a value but didn't match the assumed return type.
943         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
944         *         represents the double or float Infinity or NaN.
945         * @see Number#intValue()
946         * @deprecated 2.3.0 in favor of {@link #getIntegerOrDefault(JsonKey)} */
947        @Deprecated
948        public Integer getIntegerOrDefault(final String key, final int defaultValue){
949                Object returnable;
950                if(this.containsKey(key)){
951                        returnable = this.get(key);
952                }else{
953                        return defaultValue;
954                }
955                if(returnable == null){
956                        return null;
957                }
958                if(returnable instanceof String){
959                        /* A String can be used to construct a BigDecimal. */
960                        returnable = new BigDecimal((String)returnable);
961                }
962                return ((Number)returnable).intValue();
963        }
964
965        /** A convenience method that assumes there is a Number or String value at the given key.
966         * @param key representing where the value ought to be paired with.
967         * @return a Long representing the value paired with the key (which may involve rounding or truncation).
968         * @throws ClassCastException if the value didn't match the assumed return type.
969         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
970         *         represents the double or float Infinity or NaN.
971         * @see Number#longValue()
972         * @see JsonKey
973         * @since 2.3.0 to utilize JsonKey */
974        public Long getLong(final JsonKey key){
975                Object returnable = this.get(key.getKey());
976                if(returnable == null){
977                        return null;
978                }
979                if(returnable instanceof String){
980                        /* A String can be used to construct a BigDecimal. */
981                        returnable = new BigDecimal((String)returnable);
982                }
983                return ((Number)returnable).longValue();
984        }
985
986        /** A convenience method that assumes there is a Number or String value at the given key.
987         * @param key representing where the value ought to be stored at.
988         * @return the value stored at the key (which may involve rounding or truncation).
989         * @throws ClassCastException if the value didn't match the assumed return type.
990         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
991         *         represents the double or float Infinity or NaN.
992         * @see Number#longValue()
993         * @deprecated 2.3.0 in favor of {@link #getLong(JsonKey)} */
994        @Deprecated
995        public Long getLong(final String key){
996                Object returnable = this.get(key);
997                if(returnable == null){
998                        return null;
999                }
1000                if(returnable instanceof String){
1001                        /* A String can be used to construct a BigDecimal. */
1002                        returnable = new BigDecimal((String)returnable);
1003                }
1004                return ((Number)returnable).longValue();
1005        }
1006
1007        /** A convenience method that assumes there is a Number or String value at the given key.
1008         * @param key representing where the value ought to be paired with.
1009         * @return a Long representing the value paired with the key or JsonKey#getValue() if the key isn't present (which
1010         *         may involve rounding or truncation).
1011         * @throws ClassCastException if the value didn't match the assumed return type.
1012         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1013         *         represents the double or float Infinity or NaN.
1014         * @see Number#longValue()
1015         * @see JsonKey
1016         * @since 2.3.0 to utilize JsonKey */
1017        public Long getLongOrDefault(final JsonKey key){
1018                Object returnable;
1019                if(this.containsKey(key.getKey())){
1020                        returnable = this.get(key.getKey());
1021                }else{
1022                        returnable = key.getValue();
1023                }
1024                if(returnable == null){
1025                        return null;
1026                }
1027                if(returnable instanceof String){
1028                        /* A String can be used to construct a BigDecimal. */
1029                        returnable = new BigDecimal((String)returnable);
1030                }
1031                return ((Number)returnable).longValue();
1032        }
1033
1034        /** A convenience method that assumes there is a Number or String value at the given key.
1035         * @param key representing where the value ought to be stored at.
1036         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
1037         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
1038         *         doesn't exist.
1039         * @throws ClassCastException if there was a value but didn't match the assumed return type.
1040         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1041         *         represents the double or float Infinity or NaN.
1042         * @see Number#longValue()
1043         * @deprecated 2.3.0 in favor of {@link #getLongOrDefault(JsonKey)} */
1044        @Deprecated
1045        public Long getLongOrDefault(final String key, final long defaultValue){
1046                Object returnable;
1047                if(this.containsKey(key)){
1048                        returnable = this.get(key);
1049                }else{
1050                        return defaultValue;
1051                }
1052                if(returnable == null){
1053                        return null;
1054                }
1055                if(returnable instanceof String){
1056                        /* A String can be used to construct a BigDecimal. */
1057                        returnable = new BigDecimal((String)returnable);
1058                }
1059                return ((Number)returnable).longValue();
1060        }
1061
1062        /** A convenience method that assumes there is a Map at the given key.
1063         * @param <T> the kind of map to expect at the key. Note unless manually added, Map values will be a JsonObject.
1064         * @param key representing where the value ought to be paired with.
1065         * @return a Map representing the value paired with the key.
1066         * @throws ClassCastException if the value didn't match the assumed return type.
1067         * @see JsonKey
1068         * @since 2.3.0 to utilize JsonKey */
1069        @SuppressWarnings("unchecked")
1070        public <T extends Map<?, ?>> T getMap(final JsonKey key){
1071                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
1072                 * work. */
1073                return (T)this.get(key.getKey());
1074        }
1075
1076        /** A convenience method that assumes there is a Map at the given key.
1077         * @param <T> the kind of map to expect at the key. Note unless manually added, Map values will be a JsonObject.
1078         * @param key representing where the value ought to be stored at.
1079         * @return the value stored at the key.
1080         * @throws ClassCastException if the value didn't match the assumed return type.
1081         * @deprecated 2.3.0 in favor of {@link #getMap(JsonKey)} */
1082        @Deprecated
1083        @SuppressWarnings("unchecked")
1084        public <T extends Map<?, ?>> T getMap(final String key){
1085                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
1086                 * work. */
1087                return (T)this.get(key);
1088        }
1089
1090        /** A convenience method that assumes there is a Map at the given key.
1091         * @param <T> the kind of map to expect at the key. Note unless manually added, Map values will be a JsonObject.
1092         * @param key representing where the value ought to be paired with.
1093         * @return a Map representing the value paired with the key or JsonKey#getValue() if the key isn't present.
1094         * @throws ClassCastException if the value didn't match the assumed return type.
1095         * @see JsonKey
1096         * @since 2.3.0 to utilize JsonKey */
1097        @SuppressWarnings("unchecked")
1098        public <T extends Map<?, ?>> T getMapOrDefault(final JsonKey key){
1099                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
1100                 * work. */
1101                Object returnable;
1102                if(this.containsKey(key.getKey())){
1103                        returnable = this.get(key.getKey());
1104                }else{
1105                        returnable = key.getValue();
1106                }
1107                return (T)returnable;
1108        }
1109
1110        /** A convenience method that assumes there is a Map at the given key.
1111         * @param <T> the kind of map to expect at the key. Note unless manually added, Map values will be a JsonObject.
1112         * @param key representing where the value ought to be stored at.
1113         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
1114         * @return the value stored at the key or the default provided if the key doesn't exist.
1115         * @throws ClassCastException if there was a value but didn't match the assumed return type.
1116         * @deprecated 2.3.0 in favor of {@link #getMapOrDefault(JsonKey)} */
1117        @Deprecated
1118        @SuppressWarnings("unchecked")
1119        public <T extends Map<?, ?>> T getMapOrDefault(final String key, final T defaultValue){
1120                /* The unchecked warning is suppressed because there is no way of guaranteeing at compile time the cast will
1121                 * work. */
1122                Object returnable;
1123                if(this.containsKey(key)){
1124                        returnable = this.get(key);
1125                }else{
1126                        returnable = defaultValue;
1127                }
1128                return (T)returnable;
1129        }
1130
1131        /** A convenience method that assumes there is a Number or String value at the given key.
1132         * @param key representing where the value ought to be paired with.
1133         * @return a Short representing the value paired with the key (which may involve rounding or truncation).
1134         * @throws ClassCastException if the value didn't match the assumed return type.
1135         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1136         *         represents the double or float Infinity or NaN.
1137         * @see Number#shortValue()
1138         * @see JsonKey
1139         * @since 2.3.0 to utilize JsonKey */
1140        public Short getShort(final JsonKey key){
1141                Object returnable = this.get(key.getKey());
1142                if(returnable == null){
1143                        return null;
1144                }
1145                if(returnable instanceof String){
1146                        /* A String can be used to construct a BigDecimal. */
1147                        returnable = new BigDecimal((String)returnable);
1148                }
1149                return ((Number)returnable).shortValue();
1150        }
1151
1152        /** A convenience method that assumes there is a Number or String value at the given key.
1153         * @param key representing where the value ought to be stored at.
1154         * @return the value stored at the key (which may involve rounding or truncation).
1155         * @throws ClassCastException if the value didn't match the assumed return type.
1156         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1157         *         represents the double or float Infinity or NaN.
1158         * @see Number#shortValue()
1159         * @deprecated 2.3.0 in favor of {@link #getShort(JsonKey)} */
1160        @Deprecated
1161        public Short getShort(final String key){
1162                Object returnable = this.get(key);
1163                if(returnable == null){
1164                        return null;
1165                }
1166                if(returnable instanceof String){
1167                        /* A String can be used to construct a BigDecimal. */
1168                        returnable = new BigDecimal((String)returnable);
1169                }
1170                return ((Number)returnable).shortValue();
1171        }
1172
1173        /** A convenience method that assumes there is a Number or String value at the given key.
1174         * @param key representing where the value ought to be paired with.
1175         * @return a Short representing the value paired with the key or JsonKey#getValue() if the key isn't present (which
1176         *         may involve rounding or truncation).
1177         * @throws ClassCastException if the value didn't match the assumed return type.
1178         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1179         *         represents the double or float Infinity or NaN.
1180         * @see Number#shortValue()
1181         * @see JsonKey
1182         * @since 2.3.0 to utilize JsonKey */
1183        public Short getShortOrDefault(final JsonKey key){
1184                Object returnable;
1185                if(this.containsKey(key.getKey())){
1186                        returnable = this.get(key.getKey());
1187                }else{
1188                        returnable = key.getValue();
1189                }
1190                if(returnable == null){
1191                        return null;
1192                }
1193                if(returnable instanceof String){
1194                        /* A String can be used to construct a BigDecimal. */
1195                        returnable = new BigDecimal((String)returnable);
1196                }
1197                return ((Number)returnable).shortValue();
1198        }
1199
1200        /** A convenience method that assumes there is a Number or String value at the given key.
1201         * @param key representing where the value ought to be stored at.
1202         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
1203         * @return the value stored at the key (which may involve rounding or truncation) or the default provided if the key
1204         *         doesn't exist.
1205         * @throws ClassCastException if there was a value but didn't match the assumed return type.
1206         * @throws NumberFormatException if a String isn't a valid representation of a BigDecimal or if the Number
1207         *         represents the double or float Infinity or NaN.
1208         * @see Number#shortValue()
1209         * @deprecated 2.3.0 in favor of {@link #getShortOrDefault(JsonKey)} */
1210        @Deprecated
1211        public Short getShortOrDefault(final String key, final short defaultValue){
1212                Object returnable;
1213                if(this.containsKey(key)){
1214                        returnable = this.get(key);
1215                }else{
1216                        return defaultValue;
1217                }
1218                if(returnable == null){
1219                        return null;
1220                }
1221                if(returnable instanceof String){
1222                        /* A String can be used to construct a BigDecimal. */
1223                        returnable = new BigDecimal((String)returnable);
1224                }
1225                return ((Number)returnable).shortValue();
1226        }
1227
1228        /** A convenience method that assumes there is a Boolean, Number, or String value at the given key.
1229         * @param key representing where the value ought to be paired with.
1230         * @return a String representing the value paired with the key.
1231         * @throws ClassCastException if the value didn't match the assumed return type.
1232         * @see JsonKey
1233         * @since 2.3.0 to utilize JsonKey */
1234        public String getString(final JsonKey key){
1235                Object returnable = this.get(key.getKey());
1236                if(returnable instanceof Boolean){
1237                        returnable = returnable.toString();
1238                }else if(returnable instanceof Number){
1239                        returnable = returnable.toString();
1240                }
1241                return (String)returnable;
1242        }
1243
1244        /** A convenience method that assumes there is a Boolean, Number, or String value at the given key.
1245         * @param key representing where the value ought to be stored at.
1246         * @return the value stored at the key.
1247         * @throws ClassCastException if the value didn't match the assumed return type.
1248         * @deprecated 2.3.0 in favor of {@link #getString(JsonKey)} */
1249        @Deprecated
1250        public String getString(final String key){
1251                Object returnable = this.get(key);
1252                if(returnable instanceof Boolean){
1253                        returnable = returnable.toString();
1254                }else if(returnable instanceof Number){
1255                        returnable = returnable.toString();
1256                }
1257                return (String)returnable;
1258        }
1259
1260        /** A convenience method that assumes there is a Boolean, Number, or String value at the given key.
1261         * @param key representing where the value ought to be paired with.
1262         * @return a String representing the value paired with the key or JsonKey#getValue() if the key isn't present.
1263         * @throws ClassCastException if the value didn't match the assumed return type.
1264         * @see JsonKey
1265         * @since 2.3.0 to utilize JsonKey */
1266        public String getStringOrDefault(final JsonKey key){
1267                Object returnable;
1268                if(this.containsKey(key.getKey())){
1269                        returnable = this.get(key.getKey());
1270                }else{
1271                        returnable = key.getValue();
1272                }
1273                if(returnable instanceof Boolean){
1274                        returnable = returnable.toString();
1275                }else if(returnable instanceof Number){
1276                        returnable = returnable.toString();
1277                }
1278                return (String)returnable;
1279        }
1280
1281        /** A convenience method that assumes there is a Boolean, Number, or String value at the given key.
1282         * @param key representing where the value ought to be stored at.
1283         * @param defaultValue representing what is returned when the key isn't in the JsonObject.
1284         * @return the value stored at the key or the default provided if the key doesn't exist.
1285         * @throws ClassCastException if there was a value but didn't match the assumed return type.
1286         * @deprecated 2.3.0 in favor of {@link #getStringOrDefault(JsonKey)} */
1287        @Deprecated
1288        public String getStringOrDefault(final String key, final String defaultValue){
1289                Object returnable;
1290                if(this.containsKey(key)){
1291                        returnable = this.get(key);
1292                }else{
1293                        return defaultValue;
1294                }
1295                if(returnable instanceof Boolean){
1296                        returnable = returnable.toString();
1297                }else if(returnable instanceof Number){
1298                        returnable = returnable.toString();
1299                }
1300                return (String)returnable;
1301        }
1302
1303        /* (non-Javadoc)
1304         * @see org.json.simple.Jsonable#asJsonString() */
1305        @Override
1306        public String toJson(){
1307                final StringWriter writable = new StringWriter();
1308                try{
1309                        this.toJson(writable);
1310                }catch(final IOException caught){
1311                        /* See java.io.StringWriter. */
1312                }
1313                return writable.toString();
1314        }
1315
1316        /* (non-Javadoc)
1317         * @see org.json.simple.Jsonable#toJsonString(java.io.Writer) */
1318        @Override
1319        public void toJson(final Writer writable) throws IOException{
1320                /* Writes the map in JSON object format. */
1321                boolean isFirstEntry = true;
1322                final Iterator<Map.Entry<String, Object>> entries = this.entrySet().iterator();
1323                writable.write('{');
1324                while(entries.hasNext()){
1325                        if(isFirstEntry){
1326                                isFirstEntry = false;
1327                        }else{
1328                                writable.write(',');
1329                        }
1330                        final Map.Entry<String, Object> entry = entries.next();
1331                        writable.write(Jsoner.serialize(entry.getKey()));
1332                        writable.write(':');
1333                        writable.write(Jsoner.serialize(entry.getValue()));
1334                }
1335                writable.write('}');
1336        }
1337}