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 | } |