/* * Copyright 2008-2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mongodb; import org.bson.BSON; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonDocumentWriter; import org.bson.BsonInt32; import org.bson.BsonNull; import org.bson.BsonObjectId; import org.bson.LazyBSONCallback; import org.bson.Transformer; import org.bson.codecs.BsonValueCodecProvider; import org.bson.codecs.EncoderContext; import org.bson.codecs.ValueCodecProvider; import org.junit.Test; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import static java.util.Arrays.asList; import static org.bson.codecs.configuration.CodecRegistries.fromProviders; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class DBObjectCodecTest extends DatabaseTestCase { @Test public void testTransformers() { try { collection.save(new BasicDBObject("_id", 1).append("x", 1.1)); assertEquals(Double.class, collection.findOne().get("x").getClass()); BSON.addEncodingHook(Double.class, new Transformer() { public Object transform(final Object o) { return o.toString(); } }); collection.save(new BasicDBObject("_id", 1).append("x", 1.1)); assertEquals(String.class, collection.findOne().get("x").getClass()); BSON.clearAllHooks(); collection.save(new BasicDBObject("_id", 1).append("x", 1.1)); assertEquals(Double.class, collection.findOne().get("x").getClass()); BSON.addDecodingHook(Double.class, new Transformer() { public Object transform(final Object o) { return o.toString(); } }); assertEquals(String.class, collection.findOne().get("x").getClass()); BSON.clearAllHooks(); assertEquals(Double.class, collection.findOne().get("x").getClass()); } finally { BSON.clearAllHooks(); } } @Test public void testDBListEncoding() { BasicDBList list = new BasicDBList(); list.add(new BasicDBObject("a", 1).append("b", true)); list.add(new BasicDBObject("c", "string").append("d", 0.1)); collection.save(new BasicDBObject("l", list)); assertEquals(list, collection.findOne().get("l")); } @Test public void shouldNotGenerateIdIfPresent() { DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); DBObject document = new BasicDBObject("_id", 1); assertTrue(dbObjectCodec.documentHasId(document)); document = dbObjectCodec.generateIdIfAbsentFromDocument(document); assertTrue(dbObjectCodec.documentHasId(document)); assertEquals(new BsonInt32(1), dbObjectCodec.getDocumentId(document)); } @Test public void shouldGenerateIdIfAbsent() { DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); DBObject document = new BasicDBObject(); assertFalse(dbObjectCodec.documentHasId(document)); document = dbObjectCodec.generateIdIfAbsentFromDocument(document); assertTrue(dbObjectCodec.documentHasId(document)); assertEquals(BsonObjectId.class, dbObjectCodec.getDocumentId(document).getClass()); } @Test public void shouldRespectEncodeIdFirstPropertyInEncoderContext() { DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); // given DBObject doc = new BasicDBObject("x", 2).append("_id", 2); // when BsonDocument encodedDocument = new BsonDocument(); dbObjectCodec.encode(new BsonDocumentWriter(encodedDocument), doc, EncoderContext.builder().isEncodingCollectibleDocument(true).build()); // then assertEquals(new ArrayList<String>(encodedDocument.keySet()), asList("_id", "x")); // when encodedDocument.clear(); dbObjectCodec.encode(new BsonDocumentWriter(encodedDocument), doc, EncoderContext.builder().isEncodingCollectibleDocument(false).build()); // then assertEquals(new ArrayList<String>(encodedDocument.keySet()), asList("x", "_id")); } @Test public void shouldEncodeNull() { DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); DBObject doc = new BasicDBObject("null", null); BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); dbObjectCodec.encode(writer, doc, EncoderContext.builder().build()); assertEquals(new BsonDocument("null", BsonNull.VALUE), writer.getDocument()); } @Test public void shouldEncodedNestedMapsListsAndDocuments() { byte[] zeroOneDocumentBytes = new byte[]{19, 0, 0, 0, 16, 48, 0, 0, 0, 0, 0, 16, 49, 0, 1, 0, 0, 0, 0}; // {"0" : 0, "1", 1} Map<String, Object> zeroOneMap = new HashMap<String, Object>(); zeroOneMap.put("0", 0); zeroOneMap.put("1", 1); DBObject zeroOneDBObject = new BasicDBObject(); zeroOneDBObject.putAll(zeroOneMap); DBObject zeroOneDBList = new BasicDBList(); zeroOneDBList.putAll(zeroOneMap); List<Integer> zeroOneList = asList(0, 1); DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); DBObject doc = new BasicDBObject() .append("map", zeroOneMap) .append("dbDocument", zeroOneDBObject) .append("dbList", zeroOneDBList) .append("list", zeroOneList) .append("array", new int[] {0, 1}) .append("lazyDoc", new LazyDBObject(zeroOneDocumentBytes, new LazyBSONCallback())) .append("lazyArray", new LazyDBList(zeroOneDocumentBytes, new LazyBSONCallback())); BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); dbObjectCodec.encode(writer, doc, EncoderContext.builder().build()); BsonDocument zeroOneBsonDocument = new BsonDocument().append("0", new BsonInt32(0)).append("1", new BsonInt32(1)); BsonArray zeroOneBsonArray = new BsonArray(asList(new BsonInt32(0), new BsonInt32(1))); assertEquals(new BsonDocument("map", zeroOneBsonDocument) .append("dbDocument", zeroOneBsonDocument) .append("dbList", zeroOneBsonArray) .append("list", zeroOneBsonArray) .append("array", zeroOneBsonArray) .append("lazyDoc", zeroOneBsonDocument) .append("lazyArray", zeroOneBsonArray), writer.getDocument()); } @Test public void shouldEncodeIterableMapAsMap() { IterableMap iterableMap = new IterableMap(); iterableMap.put("first", 1); DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider(), new BsonValueCodecProvider()))); DBObject doc = new BasicDBObject("map", iterableMap); BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); dbObjectCodec.encode(writer, doc, EncoderContext.builder().build()); assertEquals(new BsonDocument("map", new BsonDocument("first", new BsonInt32(1))), writer.getDocument()); } static class IterableMap extends HashMap<String, Integer> implements Iterable<Integer> { private static final long serialVersionUID = -5090421898469363392L; @Override public Iterator<Integer> iterator() { return values().iterator(); } } }