Skip to content

Commit 1018d43

Browse files
author
Chris Cho
authored
DOCSP-12161 fundamentals codecs (#65)
* DOCSP-12161: Codecs Fundamentals page
1 parent 17f8032 commit 1018d43

File tree

8 files changed

+547
-18
lines changed

8 files changed

+547
-18
lines changed

source/fundamentals/data-formats/codecs.txt

Lines changed: 342 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,363 @@ Codecs
1111
:class: singlecol
1212

1313

14+
.. _data-formats-codecs:
15+
1416
Overview
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

20143
CodecRegistry
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

27193
CodecProvider
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

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

39295
Custom 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+

source/fundamentals/data-formats/document-data-format-pojo.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ To set up the driver to store and retrieve POJOs, we need to specify:
121121
encode/decode the data between the POJO and MongoDB document, and which
122122
POJO classes or packages that the Codecs should apply to.
123123
- A :java-docs:`CodecRegistry <apidocs/bson/org/bson/codecs/configuration/CodecRegistry.html>`
124-
instance that contains the codec provider and other related information.
124+
instance that contains the Codecs and other related information.
125125
- A ``MongoClient``, ``MongoDatabase``, or ``MongoCollection`` instance
126126
configured to use the ``CodecRegistry``.
127127
- A ``MongoCollection`` instance created with the POJO document class

0 commit comments

Comments
 (0)