@@ -11,38 +11,363 @@ Codecs
11
11
:class: singlecol
12
12
13
13
14
+ .. _data-formats-codecs:
15
+
14
16
Overview
15
17
--------
16
18
17
- - Description
18
- - Relationship between Codec, CodecRegistry, and CodecProvider
19
+ In this guide, you can learn about **Codecs** and the supporting classes that
20
+ handle the encoding and decoding of Java objects to and from BSON data in
21
+ MongoDB. The ``Codec`` abstraction allows you to map any Java type to
22
+ a corresponding BSON type. You can use this to map your domain objects
23
+ directly to and from BSON instead of using an intermediate map-based one such
24
+ as ``Document`` or ``BsonDocument``.
25
+
26
+ You can learn how to specify custom encoding and decoding logic using
27
+ the ``Codec`` abstraction and view example implementations in the following
28
+ sections:
29
+
30
+ - :ref:`Codec <codecs-codec>`
31
+ - :ref:`CodecRegistry <codecs-codecregistry>`
32
+ - :ref:`CodecProvider <codecs-codecprovider>`
33
+ - :ref:`Custom Codec Example <codecs-custom-example>`
34
+
35
+ If you are customizing encoding and decoding logic for Plain old Java objects
36
+ (POJOs), read our guide on :doc:`POJO Customization </fundamentals/data-formats/pojo-customization>`.
37
+
38
+ .. _codecs-codec:
39
+
40
+ Codec
41
+ -----
42
+
43
+ The ``Codec`` interface contains abstract methods for serializing and
44
+ deserializing Java objects to BSON data. You can define your conversion logic
45
+ between BSON and your Java object in your implementation of this interface.
46
+
47
+ To implement the ``Codec`` interface, override the ``encode()``, ``decode()``,
48
+ and ``getEncoderClass()`` abstract methods.
49
+
50
+ The ``encode()`` method requires the following parameters:
51
+
52
+ .. list-table::
53
+ :header-rows: 1
54
+ :widths: 10 20
55
+
56
+ * - Parameter Type
57
+ - Description
58
+
59
+ * - ``writer``
60
+ - An instance of a class that implements ``BsonWriter``, an interface type
61
+ that exposes methods for writing a BSON document. For example, the
62
+ ``BsonBinaryWriter`` implementation writes to a binary stream of data.
63
+ Use this instance to write your BSON value using the appropriate
64
+ write method.
65
+
66
+ * - ``value``
67
+ - The data that your implementation encodes. The type must match the type
68
+ variable assigned to your implementation.
69
+
70
+ * - ``encoderContext``
71
+ - Contains meta information about the Java object data that it encodes
72
+ to BSON including whether to store the current value in a
73
+ MongoDB collection.
74
+
75
+ This method uses the ``BsonWriter`` instance to send the encoded value to
76
+ MongoDB and does not return a value.
77
+
78
+ The ``decode()`` method returns your Java object instance populated with the
79
+ value from the BSON data. This method requires the following parameters:
80
+
81
+ .. list-table::
82
+ :header-rows: 1
83
+ :widths: 10 20
84
+
85
+ * - Parameter Type
86
+ - Description
87
+
88
+ * - ``bsonReader``
89
+ - An instance of a class that implements ``BsonReader``, an interface type
90
+ that exposes methods for reading a BSON document. For example, the
91
+ ``BsonBinaryReader`` implementation reads from a binary stream of data.
92
+
93
+ * - ``decoderContext``
94
+ - Contains information about the BSON data that it decodes to a Java
95
+ object.
96
+
97
+ The ``getEncoderClass()`` method returns a class instance of the Java class
98
+ since Java cannot infer the type due to type erasure.
99
+
100
+ .. _codecs-powerstatus-codec:
101
+
102
+ See the following code examples that show how you can implement a custom
103
+ ``Codec``.
104
+
105
+ The ``PowerStatus`` enum contains the values "ON" and "OFF" to represent
106
+ the states of an electrical switch.
107
+
108
+ .. literalinclude:: /includes/fundamentals/code-snippets/PowerStatus.java
109
+ :start-after: start class
110
+ :end-before: end class
111
+ :language: java
112
+ :dedent:
113
+
114
+ The ``PowerStatusCodec`` class implements ``Codec`` in order to convert
115
+ the Java ``enum`` values to corresponding BSON boolean values. The
116
+ ``encode()`` method converts a ``PowerStatus`` to a BSON boolean and the
117
+ ``decode()`` method performs the conversion in the opposite direction.
118
+
119
+ .. literalinclude:: /includes/fundamentals/code-snippets/PowerStatusCodec.java
120
+ :start-after: start class
121
+ :end-before: end class
122
+ :language: java
123
+ :dedent:
124
+
125
+ You can add an instance of the ``PowerStatusCodec`` to your ``CodecRegistry``
126
+ which contains a mapping between your ``Codec`` and the Java object type to
127
+ which it applies. Continue to the :ref:`CodecRegistry <codecs-codecregistry>`
128
+ section of this page to see how you can include your ``Codec``.
129
+
130
+ For more information about the classes and interfaces in this section, see the
131
+ following API documentation:
132
+
133
+ - :java-docs:`Codec <apidocs/bson/org/bson/codecs/Codec.html>`
134
+ - :java-docs:`BsonWriter <apidocs/bson/org/bson/BsonWriter.html>`
135
+ - :java-docs:`BsonBinaryWriter <apidocs/bson/org/bson/BsonBinaryWriter.html>`
136
+ - :java-docs:`EncoderContext <apidocs/bson/org/bson/codecs/EncoderContext.html>`
137
+ - :java-docs:`BsonReader <apidocs/bson/org/bson/BsonReader.html>`
138
+ - :java-docs:`DecoderContext <apidocs/bson/org/bson/codecs/DecoderContext.html>`
139
+ - :java-docs:`BsonBinaryReader <apidocs/bson/org/bson/BsonBinaryReader.html>`
140
+
141
+ .. _codecs-codecregistry:
19
142
20
143
CodecRegistry
21
144
-------------
22
145
23
- - Description
24
- - Example of setting Codec list
25
- - Example of getting a Codec
146
+ A ``CodecRegistry`` is an immutable collection of ``Codec`` instances that
147
+ encode and decode the Java classes they specify. You can use any of the
148
+ following ``CodecRegistries`` class static factory methods to construct a
149
+ ``CodecRegistry`` from the ``Codec`` instances contained in the associated
150
+ types:
151
+
152
+ - ``fromCodecs()``
153
+ - ``fromProviders()``
154
+ - ``fromRegistries()``
155
+
156
+ The following code snippet shows how to construct a ``CodecRegistry`` using
157
+ the ``fromCodecs()`` method:
158
+
159
+ .. code-block:: java
160
+ :copyable: true
161
+
162
+ CodecRegistry codecRegistry = CodecRegistries.fromCodecs(new IntegerCodec(), new PowerStatusCodec());
163
+
164
+ In the example above, we assign the ``CodecRegistry`` the following ``Codec``
165
+ implementations:
166
+
167
+ - :java-docs:`IntegerCodec </apidocs/bson/org/bson/codecs/IntegerCodec.html>`,
168
+ a ``Codec`` that converts Integers and is part of the BSON package.
169
+ - :ref:`PowerStatusCodec <codecs-powerstatus-codec>`, our sample ``Codec``
170
+ that converts certain Java strings to BSON booleans.
171
+
172
+ You can retrieve the ``Codec`` instances from the ``CodecRegistry`` instance
173
+ from the prior example using the following code:
174
+
175
+ .. code-block:: java
176
+ :copyable: true
177
+
178
+ Codec<String> powerStatusCodec = codecRegistry.get(String.class);
179
+ Codec<Integer> integerCodec = codecRegistry.get(Integer.class);
180
+
181
+ If you attempt to retrieve a ``Codec`` instance for a class that is not
182
+ registered, the ``get()`` method throws a ``CodecConfigurationException``
183
+ exception.
184
+
185
+ For more information about the classes and interfaces in this section, see the
186
+ following API documentation:
187
+
188
+ - :java-docs:`CodecRegistries </apidocs/bson/org/bson/codecs/configuration/CodecRegistries.html>`
189
+ - :java-docs:`IntegerCodec </apidocs/bson/org/bson/codecs/IntegerCodec.html>`
190
+
191
+ .. _codecs-codecprovider:
26
192
27
193
CodecProvider
28
194
-------------
29
195
30
- - Description
31
- - Example of get method implementation
196
+ A ``CodecProvider`` is an interface that contains abstract methods that create
197
+ ``Codec`` instances and assign them to a ``CodecRegistry`` instance. Similar
198
+ to the ``CodecRegistry``, the BSON library uses the ``Codec`` instances
199
+ retrieved by the ``get()`` method to convert between Java and BSON data types.
200
+
201
+ However, in cases in which you add a class that contains fields that require
202
+ corresponding ``Codec`` objects, you need to ensure that you instantiate the
203
+ ``Codec`` objects for the class' fields before you instantiate the
204
+ ``Codec`` for the class. You can use the ``CodecRegistry`` parameter in
205
+ the ``get()`` method to pass any of the ``Codec`` instances that the
206
+ ``Codec`` relies on.
207
+
208
+ The following code example shows how you can implement ``CodecProvider`` to
209
+ pass the ``MonolightCodec`` any ``Codec`` instances it needs in a
210
+ ``CodecRegistry`` instance such as the ``PowerStatusCodec`` from our prior
211
+ example:
212
+
213
+ .. literalinclude:: /includes/fundamentals/code-snippets/MonolightCodecProvider.java
214
+ :start-after: start class
215
+ :end-before: end class
216
+ :language: java
217
+ :dedent:
218
+
219
+ To see a runnable example that demonstrates read and write operations using
220
+ these ``Codec`` classes, see the :ref:`Custom Codec Example <codecs-custom-example>`
221
+ section of this guide.
222
+
223
+ When working with POJOs, consider using the ``PojoCodecProvider`` to
224
+ minimize duplicate code to convert commonly-used data types and customize
225
+ the behavior. See our
226
+ :doc:`POJO Customization guide </fundamentals/data-formats/pojo-customization>`
227
+ for more information.
228
+
229
+ For more information about the classes and interfaces in this section, see the
230
+ :java-docs:`CodecProvider API documentation <apidocs/bson/org/bson/codecs/configuration/CodecProvider.html>`.
32
231
33
232
BsonTypeClassMap
34
- ~~~~~~~~~~~~~~~~
233
+ ----------------
234
+
235
+ The ``BsonTypeClassMap`` class contains a recommended mapping between BSON
236
+ and Java types. You can use this class in your custom ``Codec`` or
237
+ ``CodecProvider`` to help you manage which Java types to decode your BSON
238
+ types to container classes that implement ``Iterable`` or ``Map`` such as
239
+ the ``Document`` class.
240
+
241
+ You can add or modify the ``BsonTypeClassMap`` default mapping by passing a
242
+ ``Map`` containing new or replacement entries.
243
+
244
+ The following code snippet shows how you can retrieve the Java class type
245
+ that corresponds to the BSON type in the default ``BsonTypeClassMap``
246
+ instance:
247
+
248
+ .. code-block:: java
249
+ :copyable: true
250
+
251
+ BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap();
252
+ Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
253
+ System.out.println("Java type: " + clazz.getName());
254
+
255
+ This code outputs the following:
256
+
257
+ .. code-block:: none
258
+ :copyable: false
259
+
260
+ Java type: java.util.List
261
+
262
+ You can modify these mappings in your instance by specifying replacements in the
263
+ ``BsonTypeClassMap`` constructor. The following code snippet shows how
264
+ you can replace the mapping for ``ARRAY`` in your ``BsonTypeClassMap``
265
+ instance with the ``Set`` class:
266
+
267
+ .. code-block:: java
268
+ :copyable: true
269
+
270
+ Map<BsonType, Class<?>> replacements = new HashMap<BsonType, Class<?>>();
271
+ replacements.put(BsonType.ARRAY, Set.class);
272
+ BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap(replacements);
273
+
274
+ Class<?> clazz = bsonTypeClassMap.get(BsonType.ARRAY);
275
+ System.out.println("Java type: " + clazz.getName());
276
+
277
+ This code outputs the following:
278
+
279
+ .. code-block:: none
280
+ :copyable: false
281
+
282
+ Java type: java.util.Set
35
283
36
- - Description
37
- - Example of how to use to specify Bson mapping
284
+ For a complete list of the default mappings, refer to the
285
+ :java-docs:`BsonTypeClassMap API documentation <apidocs/bson/org/bson/codecs/BsonTypeClassMap.html>`.
286
+
287
+ For an example of how the ``Document`` class uses ``BsonTypeClassMap``, see
288
+ the driver source code for the following classes:
289
+
290
+ - :github:`DocumentCodecProvider <mongodb/mongo-java-driver/blob/master/bson/src/main/org/bson/codecs/DocumentCodecProvider.java>`
291
+ - :github:`DocumentCodec <mongodb/mongo-java-driver/blob/master/bson/src/main/org/bson/codecs/DocumentCodec.java>`
292
+
293
+ .. _codecs-custom-example:
38
294
39
295
Custom Codec Example
40
296
--------------------
41
297
42
- - Methods to override
43
- - Encode: Describe parameters: BsonWriter, EncoderContext
44
- - Decode: Describe parameters: BsonReader, DecoderContext
45
- - Example class, demonstrating implementing encode/decode. Perhaps something like this https://stackoverflow.com/questions/45083885/decode-document-to-a-java-class-using-custom-mongo-codec
46
- - Sample query to demonstrate decode results (of a field in a POJO) using custom codec
47
- - Sample insert and resulting fields of the document to demonstrate encode
48
- - Example showing how to read/encode a document with unknown fields
298
+ In this section, we show how you can implement ``Codec`` and ``CodecProvider``
299
+ to define the encoding and decoding logic for a custom Java class. We also show
300
+ how you can specify and use your custom implementations to perform insert
301
+ and retrieve operations.
302
+
303
+ The following code snippet shows our example custom class called ``Monolight``
304
+ and its fields that we want to store and retrieve from a MongoDB collection:
305
+
306
+ .. literalinclude:: /includes/fundamentals/code-snippets/Monolight.java
307
+ :start-after: start class
308
+ :end-before: end class
309
+ :language: java
310
+ :dedent:
311
+
312
+ This class contains the following fields, each of which we need to assign a
313
+ ``Codec``:
314
+
315
+ - ``powerStatus`` describes whether the light is switched "on" or "off" for
316
+ which we use the :ref:`PowerStatusCodec <codecs-powerstatus-codec>` that
317
+ converts specific enum values to BSON booleans.
318
+ - ``colorTemperature`` describes the color of the light and contains an
319
+ ``Integer`` value for which we use the ``IntegerCodec`` included in the
320
+ BSON library.
321
+
322
+ The following code example shows how we can implement a ``Codec`` for the
323
+ ``Monolight`` class. Note that the constructor expects an instance of
324
+ ``CodecRegistry`` from which it retrieves the ``Codec`` instances it needs
325
+ to encode and decode its fields:
326
+
327
+ .. literalinclude:: /includes/fundamentals/code-snippets/MonolightCodec.java
328
+ :start-after: start class
329
+ :end-before: end class
330
+ :language: java
331
+ :dedent:
332
+
333
+ To ensure we make the ``Codec`` instances for the fields available for
334
+ ``Monolight``, we implement a custom ``CodecProvider`` shown in the following
335
+ code example:
336
+
337
+ .. literalinclude:: /includes/fundamentals/code-snippets/MonolightCodecProvider.java
338
+ :start-after: start class
339
+ :end-before: end class
340
+ :language: java
341
+ :dedent:
342
+
343
+ After defining the conversion logic, we can perform the following:
344
+
345
+ - Store data from instances of ``Monolight`` into MongoDB
346
+ - Retrieve data from MongoDB into instances of ``Monolight``
347
+
348
+ The following example class contains code that assigns the
349
+ ``MonolightCodecProvider`` to the ``MongoCollection`` instance by passing it
350
+ to the ``withCodecRegistry()`` method. The example class also inserts and
351
+ retrieves data using the ``Monolight`` class and associated ``Codecs``:
352
+
353
+ .. literalinclude:: /includes/fundamentals/code-snippets/MonolightCodecExample.java
354
+ :start-after: start class
355
+ :end-before: end class
356
+ :language: java
357
+ :dedent:
358
+
359
+ If you run the example above, you should see the following output:
360
+
361
+ .. code-block:: none
362
+ :copyable: false
363
+
364
+ [Monolight [powerStatus=ON, colorTemperature=5200]]
365
+
366
+ For more information about the methods and classes mentioned in this section,
367
+ see the following API documentation:
368
+
369
+ - :java-docs:`withCodecRegistry() <apidocs/mongodb-driver-sync/com/mongodb/client/MongoCollection.html#withCodecRegistry(org.bson.codecs.configuration.CodecRegistry)>`
370
+ - :java-docs:`MongoClientSettings.getDefaultCodecRegistry() <apidocs/mongodb-driver-core/com/mongodb/MongoClientSettings.html#getDefaultCodecRegistry()>`
371
+ - :java-docs:`Codec <apidocs/bson/org/bson/codecs/Codec.html>`
372
+ - :java-docs:`CodecProvider <apidocs/bson/org/bson/codecs/configuration/CodecProvider.html>`
373
+
0 commit comments