@@ -11,38 +11,363 @@ Codecs
1111 :class: singlecol
1212
1313
14+ .. _data-formats-codecs:
15+
1416Overview
1517--------
1618
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:
19142
20143CodecRegistry
21144-------------
22145
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:
26192
27193CodecProvider
28194-------------
29195
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>`.
32231
33232BsonTypeClassMap
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
35283
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:
38294
39295Custom Codec Example
40296--------------------
41297
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