Skip to content

Commit c3e58a0

Browse files
author
Chris Cho
authored
DOCSP-23027: BsonExtraElements Annotation (#242)
* DOCSP-23027: BsonExtraElements Annotation
1 parent 31b070e commit c3e58a0

File tree

3 files changed

+222
-2
lines changed

3 files changed

+222
-2
lines changed

source/fundamentals/data-formats/pojo-customization.txt

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,20 @@ package:
300300
nested within the field.
301301

302302
* - ``BsonExtraElements``
303-
- Specifies any extra elements that aren't already mapped to a field.
303+
- Specifies the POJO field on which to deserialize all elements that are
304+
not mapped to a field. The POJO field must be one of the following
305+
types:
306+
307+
- `Document <{+api+}/apidocs/bson/org/bson/Document.html>`__
308+
- `BsonDocument <{+api+}/apidocs/bson/org/bson/BsonDocument.html>`__
309+
- ``Map<String, Object>``
310+
311+
.. seealso::
312+
313+
:ref:`BsonExtraElements Annotation Example <bsonextraelements-annotation-code-example>`
304314

305315
The following code snippet shows a sample POJO called ``Product`` that uses
306-
the preceding annotations.
316+
several of the preceding annotations.
307317

308318
.. _bson-annotation-code-example:
309319

@@ -364,6 +374,73 @@ The annotations in the example POJO specify the following behavior:
364374
- Omit the ``relatedItems`` field and value when converting data
365375
- Use the ``Product(String name)`` constructor when instantiating the POJO
366376

377+
378+
.. _bsonextraelements-annotation-code-example:
379+
380+
BsonExtraElements Example
381+
~~~~~~~~~~~~~~~~~~~~~~~~~
382+
383+
The ``@BsonExtraElements`` annotation allows you to specify a field to
384+
deserialize data from a MongoDB document that lacks a corresponding POJO
385+
field mapping. This is useful when your application needs to work with data in
386+
a partially-defined schema. You can use this annotation to access data from
387+
any fields that do not correspond to the fields on your POJO.
388+
389+
Consider a situation in which you store and retrieve data for an online store
390+
using the :ref:`Product POJO <bson-annotation-code-example>` from the previous
391+
example. As you offer a greater variety of products for the store, you
392+
discover that you need additional fields to describe them. Instead of
393+
mapping each additional field to the POJO, you can access them from a
394+
single field annotated with ``@BsonExtraElements`` as shown in the following
395+
code example:
396+
397+
.. code-block:: java
398+
:emphasize-lines: 12-13
399+
400+
public class Product {
401+
@BsonProperty("modelName")
402+
private String name;
403+
404+
@BsonId()
405+
@BsonRepresentation(BsonType.OBJECT_ID)
406+
private String serialNumber;
407+
408+
@BsonIgnore
409+
private List<Product> relatedItems;
410+
411+
@BsonExtraElements
412+
private Document additionalInfo;
413+
414+
// ...
415+
416+
Suppose someone added additional fields for ``dimensions`` and ``weight`` to
417+
the product data such that the documents contained the following information:
418+
419+
.. code-block:: json
420+
:copyable: false
421+
:emphasize-lines: 4-5
422+
423+
{
424+
"name": "MDB0123",
425+
"serialNumber": "62e2...",
426+
"dimensions": "3x4x5",
427+
"weight": "256g"
428+
}
429+
430+
The preceding document retrieved using the ``Product`` POJO contains the
431+
following data:
432+
433+
.. code-block::
434+
:copyable: false
435+
:emphasize-lines: 5
436+
437+
ProductWithBsonExtraElements [
438+
name=MDB0123,
439+
serialNumber=62eb...,
440+
relatedItems=null,
441+
additionalInfo=Document{{dimensions=3x4x5, weight=256g}}
442+
]
443+
367444
.. _pojo-discriminators:
368445

369446
Discriminators
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fundamentals;
2+
3+
import static com.mongodb.MongoClientSettings.getDefaultCodecRegistry;
4+
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
5+
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
import org.bson.Document;
11+
import org.bson.codecs.configuration.CodecRegistry;
12+
import org.bson.codecs.pojo.PojoCodecProvider;
13+
14+
import com.mongodb.client.MongoClient;
15+
import com.mongodb.client.MongoClients;
16+
import com.mongodb.client.MongoCollection;
17+
import com.mongodb.client.MongoDatabase;
18+
import com.mongodb.client.model.Filters;
19+
import com.mongodb.client.model.Updates;
20+
import com.mongodb.client.result.UpdateResult;
21+
22+
public class BsonExtraElementsExample {
23+
24+
private static final String DOC_NAME_VALUE = "MDB0123";
25+
26+
private static CodecRegistry getCodecRegistry() {
27+
PojoCodecProvider pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
28+
return fromRegistries(getDefaultCodecRegistry(), pojoCodecProvider);
29+
}
30+
31+
private static void setup(MongoCollection<ProductWithBsonExtraElements> collection) {
32+
collection.drop();
33+
34+
ProductWithBsonExtraElements doc = new ProductWithBsonExtraElements(DOC_NAME_VALUE);
35+
collection.insertOne(doc);
36+
}
37+
38+
// Update without the POJO; match the annotations for field names
39+
private static void addOtherFields(MongoClient client) {
40+
MongoCollection<Document> collection = client.getDatabase("sample_pojo").getCollection("ProductsWithMoreInfo");
41+
42+
UpdateResult result = collection.updateOne(
43+
Filters.eq("modelName", DOC_NAME_VALUE),
44+
Updates.combine(
45+
Updates.set("dimensions", "3x4x5"),
46+
Updates.set("weight", "256g")));
47+
System.out.println(result);
48+
}
49+
50+
private static <T> void printDocuments(MongoCollection<T> collection) {
51+
List<T> products = new ArrayList<T>();
52+
collection.find().into(products);
53+
products.forEach(doc -> System.out.println(doc));
54+
}
55+
56+
public static void main(String[] args) {
57+
String uri = "mongodb://localhost:27017";
58+
59+
try (MongoClient mongoClient = MongoClients.create(uri)) {
60+
MongoDatabase database = mongoClient.getDatabase("sample_pojo").withCodecRegistry(getCodecRegistry());
61+
MongoCollection<ProductWithBsonExtraElements> collection = database.getCollection("ProductsWithMoreInfo", ProductWithBsonExtraElements.class);
62+
63+
setup(collection);
64+
addOtherFields(mongoClient);
65+
printDocuments(collection);
66+
}
67+
}
68+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package fundamentals;
2+
3+
import java.util.List;
4+
5+
import org.bson.BsonType;
6+
import org.bson.Document;
7+
import org.bson.codecs.pojo.annotations.BsonCreator;
8+
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
9+
import org.bson.codecs.pojo.annotations.BsonExtraElements;
10+
import org.bson.codecs.pojo.annotations.BsonId;
11+
import org.bson.codecs.pojo.annotations.BsonIgnore;
12+
import org.bson.codecs.pojo.annotations.BsonProperty;
13+
import org.bson.codecs.pojo.annotations.BsonRepresentation;
14+
15+
@BsonDiscriminator(value="ProductWithBsonExtraElements", key="_cls")
16+
public class ProductWithBsonExtraElements {
17+
18+
@BsonProperty("modelName")
19+
private String name;
20+
21+
@BsonId()
22+
@BsonRepresentation(BsonType.OBJECT_ID)
23+
private String serialNumber;
24+
25+
@BsonIgnore
26+
private List<ProductPojo> relatedItems;
27+
28+
@BsonExtraElements
29+
private Document additionalInfo;
30+
31+
@BsonCreator
32+
public ProductWithBsonExtraElements(
33+
@BsonProperty("modelName") String name) {
34+
this.name = name;
35+
}
36+
37+
public String getName() {
38+
return name;
39+
}
40+
41+
public void setName(String name) {
42+
this.name = name;
43+
}
44+
45+
public String getSerialNumber() {
46+
return serialNumber;
47+
}
48+
49+
public void setSerialNumber(String serialNumber) {
50+
this.serialNumber = serialNumber;
51+
}
52+
53+
public List<ProductPojo> getRelatedItems() {
54+
return relatedItems;
55+
}
56+
57+
public void setRelatedItems(List<ProductPojo> relatedItems) {
58+
this.relatedItems = relatedItems;
59+
}
60+
61+
public Document getAdditionalInfo() {
62+
return additionalInfo;
63+
}
64+
65+
public void setAdditionalInfo(Document additionalInfo) {
66+
this.additionalInfo = additionalInfo;
67+
}
68+
69+
@Override
70+
public String toString() {
71+
return "ProductWithBsonExtraElements [name=" + name + ", serialNumber=" + serialNumber + ", relatedItems="
72+
+ relatedItems + ", additionalInfo=" + additionalInfo + "]";
73+
}
74+
75+
}

0 commit comments

Comments
 (0)