| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| Json |
|
| 2.8;2.8 |
| 1 | /* | |
| 2 | * #%L | |
| 3 | * Json.java - mongodb-async-driver - Allanbank Consulting, Inc. | |
| 4 | * %% | |
| 5 | * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc. | |
| 6 | * %% | |
| 7 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 8 | * you may not use this file except in compliance with the License. | |
| 9 | * You may obtain a copy of the License at | |
| 10 | * | |
| 11 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 12 | * | |
| 13 | * Unless required by applicable law or agreed to in writing, software | |
| 14 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 16 | * See the License for the specific language governing permissions and | |
| 17 | * limitations under the License. | |
| 18 | * #L% | |
| 19 | */ | |
| 20 | ||
| 21 | package com.allanbank.mongodb.bson.json; | |
| 22 | ||
| 23 | import java.io.Reader; | |
| 24 | import java.io.StringReader; | |
| 25 | import java.io.StringWriter; | |
| 26 | import java.io.Writer; | |
| 27 | ||
| 28 | import com.allanbank.mongodb.bson.Document; | |
| 29 | import com.allanbank.mongodb.bson.DocumentAssignable; | |
| 30 | import com.allanbank.mongodb.bson.DocumentReference; | |
| 31 | import com.allanbank.mongodb.bson.Element; | |
| 32 | import com.allanbank.mongodb.bson.element.BinaryElement; | |
| 33 | import com.allanbank.mongodb.bson.element.BooleanElement; | |
| 34 | import com.allanbank.mongodb.bson.element.DoubleElement; | |
| 35 | import com.allanbank.mongodb.bson.element.IntegerElement; | |
| 36 | import com.allanbank.mongodb.bson.element.JsonSerializationVisitor; | |
| 37 | import com.allanbank.mongodb.bson.element.LongElement; | |
| 38 | import com.allanbank.mongodb.bson.element.MaxKeyElement; | |
| 39 | import com.allanbank.mongodb.bson.element.MinKeyElement; | |
| 40 | import com.allanbank.mongodb.bson.element.MongoTimestampElement; | |
| 41 | import com.allanbank.mongodb.bson.element.NullElement; | |
| 42 | import com.allanbank.mongodb.bson.element.ObjectIdElement; | |
| 43 | import com.allanbank.mongodb.bson.element.RegularExpressionElement; | |
| 44 | import com.allanbank.mongodb.bson.element.StringElement; | |
| 45 | import com.allanbank.mongodb.bson.element.SymbolElement; | |
| 46 | import com.allanbank.mongodb.bson.element.TimestampElement; | |
| 47 | import com.allanbank.mongodb.error.JsonException; | |
| 48 | import com.allanbank.mongodb.error.JsonParseException; | |
| 49 | ||
| 50 | /** | |
| 51 | * Json provides a simplified interface for parsing JSON documents into BSON | |
| 52 | * {@link Document}s and also serializing BSON {@link Document}s into JSON text. | |
| 53 | * <p> | |
| 54 | * Basic JSON types are parsed as follows: | |
| 55 | * <dl> | |
| 56 | * <dt>{@code true} or {@code false} token</dt> | |
| 57 | * <dd>Creates an {@link BooleanElement}. <br/> | |
| 58 | * <code>{ a : true }</code> or <code>{ a : false }</code></dd> | |
| 59 | * <dt>{@code null} token</dt> | |
| 60 | * <dd>Creates an {@link NullElement}. <br/> | |
| 61 | * <code>{ a : null }</code></dd> | |
| 62 | * <dt>Other Non-Quoted Strings</dt> | |
| 63 | * <dd>Creates a {@link SymbolElement}:<br/> | |
| 64 | * <code>{ a : b }</code></dd> | |
| 65 | * <dt>Quoted Strings (either single or double quotes)</dt> | |
| 66 | * <dd>Creates a {@link StringElement}:<br/> | |
| 67 | * <code>{ a : 'b' }</code> or <code>{ a : "b" }</code></dd> | |
| 68 | * <dt>Integers (Numbers without a {@code . } or exponent)</dt> | |
| 69 | * <dd>Creates an {@link IntegerElement} if within the range [ | |
| 70 | * {@link Integer#MIN_VALUE}, {@link Integer#MAX_VALUE}], otherwise a | |
| 71 | * {@link LongElement}. Value is parsed by {@link Long#parseLong(String)}.<br/> | |
| 72 | * <code>{ a : 1234 }</code> or <code>{ a : 123456789012 }</code></dd> | |
| 73 | * <dt>Doubles (Numbers with a {@code . } or exponent)</dt> | |
| 74 | * <dd>Creates an {@link DoubleElement}. Value is parsed by | |
| 75 | * {@link Double#parseDouble(String)}.<br/> | |
| 76 | * <code>{ a : 1.2 }</code> or <code>{ a : 1e12 }</code></dd> | |
| 77 | * </p> | |
| 78 | * <p> | |
| 79 | * In addition to the basic JSON types the parser also supports the following | |
| 80 | * standard MongoDB/BSON extensions: | |
| 81 | * </p> | |
| 82 | * <dl> | |
| 83 | * <dt>BinData</dt> | |
| 84 | * <dd>Creates a {@link BinaryElement}. The first field is the sub-type, | |
| 85 | * normally zero. The second field is the base64 encoded binary value: <br/> | |
| 86 | * <code>{ a : BinData(0, "VVU=") }</code> or | |
| 87 | * <code>{ a : { $binary:"VVU=", $type:0 } }</code></dd> | |
| 88 | * <code>{ a : { $binary:"VVU=", $type: '0x00' } }</code></dd> | |
| 89 | * <code>{ a : { $binary:"VVU=", $type: '00' } }</code></dd> | |
| 90 | * <dt>HexData</dt> | |
| 91 | * <dd>Creates a {@link BinaryElement}. The first field is the sub-type, | |
| 92 | * normally zero. The second field is the hex encoded binary value: <br/> | |
| 93 | * <code>{ a : HexData(0, "cafe") }</code></dd> | |
| 94 | * <dt>ISODate</dt> | |
| 95 | * <dd>Creates a {@link TimestampElement}: <br/> | |
| 96 | * <code>{ a : ISODate("2012-07-14T01:00:00.000") }</code> or | |
| 97 | * <code>{ a : { $date : "2012-07-14T01:00:00.000" } }</code> or | |
| 98 | * <code>{ a : { $date : 1234567890 } }</code></dd> | |
| 99 | * <dt>MaxKey</dt> | |
| 100 | * <dd>Creates a {@link MaxKeyElement}: <br/> | |
| 101 | * <code>{ a : MaxKey }</code> or <code>{ a : MaxKey() }</code></dd> | |
| 102 | * <dt>MinKey</dt> | |
| 103 | * <dd>Creates a {@link MinKeyElement}: <br/> | |
| 104 | * <code>{ a : MinKey }</code> or <code>{ a : MinKey() }</code></dd> | |
| 105 | * <dt>NumberLong</dt> | |
| 106 | * <dd>Creates a {@link LongElement}: <br/> | |
| 107 | * <code>{ a : NumberLong("123456789") }</code></dd> | |
| 108 | * <dt>ObjectId</dt> | |
| 109 | * <dd>Creates an {@link ObjectIdElement}. The string is the hex encoding of the | |
| 110 | * 128 bit value: <br/> | |
| 111 | * <code>{ a : ObjectId("4e9d87aa5825b60b637815a6") }</code> or | |
| 112 | * <code>{ a : { $oid : "4e9d87aa5825b60b637815a6" } }</code></dd> | |
| 113 | * <dt>$regex</dt> | |
| 114 | * <dd>Creates an {@link RegularExpressionElement}: <br/> | |
| 115 | * <code>{ a : { $regex : 'cat' , $options : 'i' } }</code></dd> | |
| 116 | * <dt>Timestamp</dt> | |
| 117 | * <dd>Creates a {@link MongoTimestampElement}. The first value is the seconds | |
| 118 | * since the UNIX epoch. The second value is an ordinal: <br/> | |
| 119 | * <code>{ a : Timestamp(0,0) }</code> or | |
| 120 | * <code>{ a : { $timestamp : { t : 0, i : 0 } } }</code></dd> | |
| 121 | * </dl> | |
| 122 | * <p> | |
| 123 | * The following non-standard extensions are also provided. These extensions may | |
| 124 | * be deprecated in future releases if standard extensions are created: | |
| 125 | * </p> | |
| 126 | * <dl> | |
| 127 | * <dt>DBPointer</dt> | |
| 128 | * <dd>Creates a {@link com.allanbank.mongodb.bson.element.DBPointerElement | |
| 129 | * DBPointerElement}:<br/> | |
| 130 | * <code>{ a : DBPointer("db", 'collection', ObjectId("4e9d87aa5825b60b637815a6") ) }</code> | |
| 131 | * <br/> | |
| 132 | * <b>Note</b>: DBPointers are deprecated in favor of the | |
| 133 | * {@link DocumentReference DBRef} convention</dd> | |
| 134 | * </dl> | |
| 135 | * <p> | |
| 136 | * <b>Note</b>: Currently serialization/parsing round trip is not supported for | |
| 137 | * the following {@link Element} types: | |
| 138 | * <ul> | |
| 139 | * <li>{@link com.allanbank.mongodb.bson.element.JavaScriptElement | |
| 140 | * JavaScriptElement}</li> | |
| 141 | * <li>{@link com.allanbank.mongodb.bson.element.JavaScriptWithScopeElement | |
| 142 | * JavaScriptWithScopeElement}</li> | |
| 143 | * </ul> | |
| 144 | * </p> | |
| 145 | * | |
| 146 | * @see <a | |
| 147 | * href="http://docs.mongodb.org/manual/reference/mongodb-extended-json/">MongoDB | |
| 148 | * Extended JSON</a> | |
| 149 | * @api.yes This class is part of the driver's API. Public and protected members | |
| 150 | * will be deprecated for at least 1 non-bugfix release (version | |
| 151 | * numbers are <major>.<minor>.<bugfix>) before being | |
| 152 | * removed or modified. | |
| 153 | * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved | |
| 154 | */ | |
| 155 | public class Json { | |
| 156 | ||
| 157 | /** | |
| 158 | * Parses the document from the reader into a BSON {@link Document}. | |
| 159 | * <p> | |
| 160 | * See the class documentation for important limitations on round trip | |
| 161 | * serialization and parsing. | |
| 162 | * </p> | |
| 163 | * | |
| 164 | * @param input | |
| 165 | * The source of the document to read. | |
| 166 | * @return The {@link Document} representation of the JSON document. | |
| 167 | * @throws JsonParseException | |
| 168 | * On a failure to parse the JSON document. | |
| 169 | */ | |
| 170 | public static Document parse(final Reader input) throws JsonParseException { | |
| 171 | final JsonParser parser = new JsonParser(); | |
| 172 | ||
| 173 | try { | |
| 174 | final Object result = parser.parse(input); | |
| 175 | 81 | if (result instanceof Document) { |
| 176 | 80 | return (Document) result; |
| 177 | } | |
| 178 | ||
| 179 | 1 | throw new JsonParseException( |
| 180 | "Unknown type returned from the parsed document: " + result); | |
| 181 | } | |
| 182 | 11 | catch (final ParseException pe) { |
| 183 | 11 | if (pe.currentToken != null) { |
| 184 | throw new JsonParseException(pe.getMessage(), pe, | |
| 185 | pe.currentToken.beginLine, pe.currentToken.beginColumn); | |
| 186 | } | |
| 187 | 0 | throw new JsonParseException(pe); |
| 188 | } | |
| 189 | 1 | catch (final RuntimeException re) { |
| 190 | 1 | throw new JsonParseException(re); |
| 191 | } | |
| 192 | } | |
| 193 | ||
| 194 | /** | |
| 195 | * Parses the document from the reader into a BSON {@link Document}. | |
| 196 | * <p> | |
| 197 | * This method is equivalent to: <blockquote> | |
| 198 | * | |
| 199 | * <pre> | |
| 200 | * <code> | |
| 201 | * parse(new StringReader(input)); | |
| 202 | * </code> | |
| 203 | * </pre> | |
| 204 | * | |
| 205 | * </blockquote> | |
| 206 | * </p> | |
| 207 | * <p> | |
| 208 | * See the class documentation for important limitations on round trip | |
| 209 | * serialization and parsing. | |
| 210 | * </p> | |
| 211 | * | |
| 212 | * @param input | |
| 213 | * The source of the document to read. | |
| 214 | * @return The {@link Document} representation of the JSON document. | |
| 215 | * @throws JsonParseException | |
| 216 | * On a failure to parse the JSON document. | |
| 217 | */ | |
| 218 | public static Document parse(final String input) throws JsonParseException { | |
| 219 | 90 | return parse(new StringReader(input)); |
| 220 | } | |
| 221 | ||
| 222 | /** | |
| 223 | * Serializes the {@link Document} to an equivalent JSON document. | |
| 224 | * <p> | |
| 225 | * See the class documentation for important limitations on round trip | |
| 226 | * serialization and parsing. | |
| 227 | * </p> | |
| 228 | * | |
| 229 | * @param document | |
| 230 | * The document to conver to a JSON document. | |
| 231 | * @return The JSON document text. | |
| 232 | * @throws JsonException | |
| 233 | * On a failure to write the JSON document. | |
| 234 | */ | |
| 235 | public static String serialize(final DocumentAssignable document) | |
| 236 | throws JsonException { | |
| 237 | 1 | final StringWriter writer = new StringWriter(); |
| 238 | ||
| 239 | 1 | serialize(document, writer); |
| 240 | ||
| 241 | 1 | return writer.toString(); |
| 242 | } | |
| 243 | ||
| 244 | /** | |
| 245 | * Serializes the {@link Document} to an equivalent JSON document. | |
| 246 | * <p> | |
| 247 | * See the class documentation for important limitations on round trip | |
| 248 | * serialization and parsing. | |
| 249 | * </p> | |
| 250 | * | |
| 251 | * @param document | |
| 252 | * The document to conver to a JSON document. | |
| 253 | * @param sink | |
| 254 | * The sink for the JSON document text. | |
| 255 | * @throws JsonException | |
| 256 | * On a failure to write the JSON document. | |
| 257 | */ | |
| 258 | public static void serialize(final DocumentAssignable document, | |
| 259 | final Writer sink) throws JsonException { | |
| 260 | 1 | final JsonSerializationVisitor visitor = new JsonSerializationVisitor( |
| 261 | sink, true); | |
| 262 | 1 | document.asDocument().accept(visitor); |
| 263 | 1 | } |
| 264 | ||
| 265 | /** | |
| 266 | * Creates a new Json onbject - hidden. | |
| 267 | */ | |
| 268 | private Json() { | |
| 269 | 0 | super(); |
| 270 | 0 | } |
| 271 | ||
| 272 | } |