Skip to content

Commit 7c94562

Browse files
authored
DOCSP-51341: Extended JSON (#116)
* DOCSP-51341: Extended JSON * snooty * edits * build errors * NH feedback
1 parent 294b18c commit 7c94562

File tree

3 files changed

+305
-5
lines changed

3 files changed

+305
-5
lines changed

source/data-formats.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ Data Formats
2525
Data Classes </data-formats/data-format-data-class>
2626
BSON </data-formats/bson>
2727
Time Series </data-formats/time-series>
28-
29-
.. TODO: /data-formats/extended-json
28+
Extended JSON </data-formats/extended-json>
3029

3130
Overview
3231
--------
@@ -49,6 +48,4 @@ sections:
4948
:ref:`kotlin-sync-data-format-data-classes` guide.
5049
- Learn how to work with the BSON data format in the :ref:`kotlin-sync-bson` guide.
5150
- Learn how to store and interact with time series data in the :ref:`kotlin-sync-time-series` guide.
52-
53-
.. TODO: Uncomment these as pages get built
54-
.. - Learn how to use the Extended JSON format in the :ref:`kotlin-sync-extended-json` guide.
51+
- Learn how to read and write Extended JSON strings in the :ref:`kotlin-sync-extended-json` guide.

source/data-formats/extended-json.txt

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
.. _kotlin-sync-extended-json:
2+
3+
============================
4+
Work with Extended JSON Data
5+
============================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 2
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: code examples, bson, relaxed, canonical
19+
20+
.. sharedinclude:: dbx/extended-json.rst
21+
22+
.. replacement:: driver-specific-text-extended
23+
24+
.. replacement:: driver-specific-text-relaxed
25+
26+
The {+driver-short+} uses Relaxed mode by default.
27+
28+
.. replacement:: driver-specific-text-shell
29+
30+
Read Extended JSON
31+
------------------
32+
33+
This section shows how to read Extended JSON values into {+language+}
34+
objects in the following ways:
35+
36+
- :ref:`kotlin-sync-read-ejson-doc`
37+
- :ref:`kotlin-sync-read-ejson-jsonreader`
38+
39+
.. _kotlin-sync-read-ejson-doc:
40+
41+
Use the Document Classes
42+
~~~~~~~~~~~~~~~~~~~~~~~~
43+
44+
To read a Extended JSON string into a {+language+} document object, call
45+
the ``parse()`` static method from the ``Document`` or ``BsonDocument`` class.
46+
This method parses the Extended JSON string and stores its data in an instance of the specified
47+
document class.
48+
49+
The following example uses the ``parse()`` method to read an Extended JSON string
50+
into a ``Document`` object:
51+
52+
.. io-code-block::
53+
:copyable:
54+
55+
.. input:: /includes/data-formats/ext-json.kt
56+
:language: kotlin
57+
:start-after: start-read-doc
58+
:end-before: end-read-doc
59+
:dedent:
60+
61+
.. output::
62+
:visible: false
63+
64+
Document{{_id=507f1f77bcf86cd799439011, myNumber=4794261}}
65+
66+
.. _kotlin-sync-read-ejson-jsonreader:
67+
68+
Use the JsonReader Class
69+
~~~~~~~~~~~~~~~~~~~~~~~~
70+
71+
To read an Extended JSON string into {+language+} objects without using
72+
the {+driver-short+}'s document classes, use the BSON library's ``JsonReader`` class.
73+
This class contains methods to sequentially parse the fields and values
74+
of the Extended JSON string and return them as {+language+} objects.
75+
The driver's document classes also use this class to parse Extended JSON.
76+
77+
The following code uses methods provided by the ``JsonReader`` class to convert
78+
an Extended JSON string into {+language+} objects:
79+
80+
.. io-code-block::
81+
:copyable:
82+
83+
.. input:: /includes/data-formats/ext-json.kt
84+
:language: kotlin
85+
:start-after: start-read-bson
86+
:end-before: end-read-bson
87+
:dedent:
88+
89+
.. output::
90+
:visible: false
91+
92+
507f1f77bcf86cd799439011 is type: org.bson.types.ObjectId
93+
4794261 is type: kotlin.Long
94+
95+
Write Extended JSON
96+
-------------------
97+
98+
This section shows how to write Extended JSON values from {+language+}
99+
objects in the following ways:
100+
101+
- :ref:`kotlin-sync-write-ejson-doc`
102+
- :ref:`kotlin-sync-write-ejson-jsonwriter`
103+
104+
.. _kotlin-sync-write-ejson-doc:
105+
106+
Use the Document Classes
107+
~~~~~~~~~~~~~~~~~~~~~~~~
108+
109+
To write an Extended JSON string from a ``Document`` or ``BsonDocument``
110+
object, call the ``toJson()`` method. You can pass this method a
111+
``JsonWriterSettings`` object parameter to specify the Extended JSON format.
112+
113+
The following example writes ``Document`` data as Relaxed mode Extended
114+
JSON:
115+
116+
.. io-code-block::
117+
:copyable:
118+
119+
.. input:: /includes/data-formats/ext-json.kt
120+
:language: kotlin
121+
:start-after: start-write-doc
122+
:end-before: end-write-doc
123+
:dedent:
124+
125+
.. output::
126+
:visible: false
127+
128+
{"_id": {"$oid": "507f1f77bcf86cd799439012"}, "createdAt": {"$date": "2020-09-30T21:00:09Z"}, "myNumber": 4794261}
129+
130+
.. _kotlin-sync-write-ejson-jsonwriter:
131+
132+
Use the JsonWriter Class
133+
~~~~~~~~~~~~~~~~~~~~~~~~
134+
135+
To output an Extended JSON string from data stored in {+language+} objects, you can use
136+
the BSON library's ``JsonWriter`` class. To construct a ``JsonWriter`` object,
137+
pass a subclass of a Java ``Writer`` to specify how you want to output the Extended
138+
JSON. Optionally, you can pass a ``JsonWriterSettings`` instance to specify options,
139+
such as the Extended JSON format. By default, ``JsonWriter`` uses the Relaxed mode
140+
format. The {+driver-short+}'s document classes also use this class to convert BSON
141+
to Extended JSON.
142+
143+
The following example uses a ``JsonWriter`` object to create
144+
Canonical mode Extended JSON string values and output them to ``System.out``:
145+
146+
.. io-code-block::
147+
:copyable:
148+
149+
.. input:: /includes/data-formats/ext-json.kt
150+
:language: kotlin
151+
:start-after: start-write-bson
152+
:end-before: end-write-bson
153+
:dedent:
154+
155+
.. output::
156+
:visible: false
157+
158+
{"_id": {"$oid": "507f1f77bcf86cd799439012"}, "myNumber": {"$numberLong": "11223344"}}
159+
160+
Custom BSON Type Conversion
161+
---------------------------
162+
163+
In addition to specifying the Extended JSON output format, you
164+
can further customize the output by adding converters to your
165+
``JsonWriterSettings`` object. These converter methods specify logic
166+
for handling different data types during the conversion process.
167+
168+
The following example converts the same document as the :ref:`kotlin-sync-write-ejson-doc`
169+
example. However, this example defines the ``objectIdConverter()`` and ``dateTimeConverter()``
170+
converter methods in a ``JsonWriterSettings`` object to simplify the Relaxed mode
171+
Extended JSON output:
172+
173+
.. io-code-block::
174+
:copyable:
175+
176+
.. input:: /includes/data-formats/ext-json.kt
177+
:language: kotlin
178+
:start-after: start-custom-conversion
179+
:end-before: end-custom-conversion
180+
:dedent:
181+
182+
.. output::
183+
:visible: false
184+
185+
{"_id": "507f1f77bcf86cd799439012", "createdAt": "2020-09-30T21:00:09Z", "myNumber": 4794261}
186+
187+
API Documentation
188+
-----------------
189+
190+
To learn more about any of the methods or types discussed in this
191+
guide, see the following API documentation:
192+
193+
- `Document <{+api-root+}/bson/org/bson/Document.html>`__
194+
- `Document.parse() <{+api-root+}/bson/org/bson/Document.html#parse(java.lang.String)>`__
195+
- `JsonReader <{+api-root+}/bson/org/bson/json/JsonReader.html>`__
196+
- `JsonWriter <{+api-root+}/bson/org/bson/json/JsonWriter.html>`__
197+
- `Document.toJson() <{+api-root+}/bson/org/bson/Document.html#toJson()>`__
198+
- `JsonWriterSettings <{+api-root+}/bson/org/bson/json/JsonWriterSettings.html>`__
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package org.example
2+
3+
import org.bson.json.JsonWriter
4+
import org.bson.json.JsonWriterSettings
5+
import java.util.Date
6+
import org.bson.Document
7+
import org.bson.json.JsonMode
8+
import org.bson.json.JsonReader
9+
import org.bson.types.ObjectId
10+
import java.time.Instant
11+
import java.time.ZoneOffset
12+
import java.time.format.DateTimeFormatter
13+
import java.io.BufferedWriter
14+
import java.io.OutputStreamWriter
15+
16+
fun main() {
17+
18+
// start-read-doc
19+
val ejsonStr = """
20+
{
21+
"_id": { "$${"oid"}": "507f1f77bcf86cd799439011" },
22+
"myNumber": { "$${"numberLong"}": "4794261" }
23+
}
24+
""".trimIndent()
25+
26+
val doc = Document.parse(ejsonStr)
27+
println(doc)
28+
// end-read-doc
29+
30+
// start-read-bson
31+
val string = """
32+
{
33+
"_id": { "$${"oid"}": "507f1f77bcf86cd799439011" },
34+
"myNumber": { "$${"numberLong"}": "4794261" }
35+
}
36+
""".trimIndent()
37+
38+
val jsonReader = JsonReader(string)
39+
jsonReader.readStartDocument()
40+
41+
// Reads the "_id" field value
42+
jsonReader.readName("_id")
43+
val id = jsonReader.readObjectId()
44+
45+
// Reads the "myNumber" field value
46+
jsonReader.readName("myNumber")
47+
val myNumber = jsonReader.readInt64()
48+
49+
jsonReader.readEndDocument()
50+
51+
println("$id is type: ${id::class.qualifiedName}")
52+
println("$myNumber is type: ${myNumber::class.qualifiedName}")
53+
54+
jsonReader.close()
55+
// end-read-bson
56+
57+
// start-write-doc
58+
val doc = Document()
59+
.append("_id", ObjectId("507f1f77bcf86cd799439012"))
60+
.append("createdAt", Date.from(Instant.ofEpochMilli(1601499609000L)))
61+
.append("myNumber", 4794261)
62+
63+
val settings = JsonWriterSettings.builder()
64+
.outputMode(JsonMode.RELAXED)
65+
.build()
66+
67+
println(doc.toJson(settings))
68+
// end-write-doc
69+
70+
// start-write-bson
71+
val settings = JsonWriterSettings.builder()
72+
.outputMode(JsonMode.EXTENDED)
73+
.build()
74+
75+
JsonWriter(BufferedWriter(OutputStreamWriter(System.out)), settings).use { jsonWriter ->
76+
jsonWriter.writeStartDocument()
77+
jsonWriter.writeName("_id")
78+
jsonWriter.writeObjectId(ObjectId("507f1f77bcf86cd799439012"))
79+
jsonWriter.writeName("myNumber")
80+
jsonWriter.writeInt64(11223344L)
81+
jsonWriter.writeEndDocument()
82+
jsonWriter.flush()
83+
}
84+
// end-write-bson
85+
86+
// start-custom-conversion
87+
val settings = JsonWriterSettings.builder()
88+
.outputMode(JsonMode.RELAXED)
89+
.objectIdConverter { value, writer ->
90+
writer.writeString(value.toHexString())
91+
}
92+
.dateTimeConverter { value, writer ->
93+
val zonedDateTime = Instant.ofEpochMilli(value).atZone(ZoneOffset.UTC)
94+
writer.writeString(DateTimeFormatter.ISO_DATE_TIME.format(zonedDateTime))
95+
}
96+
.build()
97+
98+
val doc = Document()
99+
.append("_id", ObjectId("507f1f77bcf86cd799439012"))
100+
.append("createdAt", Date.from(Instant.ofEpochMilli(1601499609000L)))
101+
.append("myNumber", 4794261)
102+
103+
println(doc.toJson(settings))
104+
// end-custom-conversion
105+
}

0 commit comments

Comments
 (0)