de.undercouch.bson4jackson.BsonGeneratorTest.java Source code

Java tutorial

Introduction

Here is the source code for de.undercouch.bson4jackson.BsonGeneratorTest.java

Source

// Copyright 2010-2011 Michel Kraemer
//
// 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 de.undercouch.bson4jackson;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Pattern;

import org.bson.BSONDecoder;
import org.bson.BSONObject;
import org.bson.BasicBSONDecoder;
import org.bson.types.BSONTimestamp;
import org.bson.types.Code;
import org.bson.types.CodeWScope;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;

import de.undercouch.bson4jackson.io.DynamicOutputBuffer;
import de.undercouch.bson4jackson.types.JavaScript;
import de.undercouch.bson4jackson.types.ObjectId;
import de.undercouch.bson4jackson.types.Timestamp;

/**
 * Tests {@link BsonGenerator}
 * @author Michel Kraemer
 */
public class BsonGeneratorTest {
    @Test
    public void generatePrimitives() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("Int32", 5);
        data.put("Boolean1", true);
        data.put("Boolean2", false);
        data.put("String", "Hello");
        data.put("Long", 1234L);
        data.put("Null", null);
        data.put("Float", 1234.1234f);
        data.put("Double", 5678.5678);

        //BigInteger that can be serialized as an Integer
        data.put("BigInt1", BigInteger.valueOf(Integer.MAX_VALUE));

        //BigInteger that can be serialized as a Long
        BigInteger bi2 = BigInteger.valueOf(Integer.MAX_VALUE).multiply(BigInteger.valueOf(2));
        data.put("BigInt2", bi2);

        //BigInteger that will be serialized as a String
        BigInteger bi3 = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(Long.MAX_VALUE));
        data.put("BigInt3", bi3);

        BSONObject obj = generateAndParse(data);

        assertEquals(5, obj.get("Int32"));
        assertEquals(true, obj.get("Boolean1"));
        assertEquals(false, obj.get("Boolean2"));
        assertEquals("Hello", obj.get("String"));
        assertEquals(1234L, obj.get("Long"));
        assertEquals(null, obj.get("Null"));
        assertEquals(1234.1234f, (Double) obj.get("Float"), 0.00001);
        assertEquals(5678.5678, (Double) obj.get("Double"), 0.00001);
        assertEquals(Integer.MAX_VALUE, obj.get("BigInt1"));
        assertEquals(Long.valueOf(Integer.MAX_VALUE) * 2L, obj.get("BigInt2"));
        assertEquals(bi3.toString(), obj.get("BigInt3"));
    }

    @Test
    public void stream() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonFactory fac = new BsonFactory();
        fac.enable(BsonGenerator.Feature.ENABLE_STREAMING);
        BsonGenerator gen = fac.createGenerator(baos);
        byte[] dummy = new byte[DynamicOutputBuffer.DEFAULT_BUFFER_SIZE * 3 / 2];
        gen.writeStartObject();
        gen.writeFieldName("Test");
        gen.writeBinary(dummy);

        assertEquals(DynamicOutputBuffer.DEFAULT_BUFFER_SIZE, baos.size());

        gen.writeEndObject();
        gen.writeStartObject();
        gen.writeFieldName("Test");
        gen.writeBinary(dummy);

        assertEquals(DynamicOutputBuffer.DEFAULT_BUFFER_SIZE * 3, baos.size());

        gen.writeEndObject();
        gen.close();

        assertTrue(baos.size() > DynamicOutputBuffer.DEFAULT_BUFFER_SIZE * 3);
    }

    private void assertRaw(byte[] r) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(r);
        BSONDecoder decoder = new BasicBSONDecoder();
        BSONObject obj = decoder.readObject(bais);
        byte[] o = (byte[]) obj.get("Test");
        CharBuffer buf = ByteBuffer.wrap(o).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
        assertEquals(2, buf.remaining());
        char a = buf.get();
        char b = buf.get();
        assertEquals('a', a);
        assertEquals('b', b);
    }

    @Test
    public void rawChar() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonGenerator gen = new BsonGenerator(JsonGenerator.Feature.collectDefaults(), 0, baos);
        gen.writeStartObject();
        gen.writeFieldName("Test");
        gen.writeRaw(new char[] { 'a', 'b' }, 0, 2);
        gen.writeEndObject();
        gen.close();
        assertRaw(baos.toByteArray());
    }

    @Test
    public void rawString() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonGenerator gen = new BsonGenerator(JsonGenerator.Feature.collectDefaults(), 0, baos);
        gen.writeStartObject();
        gen.writeFieldName("Test");
        gen.writeRaw("ab");
        gen.writeEndObject();
        gen.close();
        assertRaw(baos.toByteArray());
    }

    @Test
    public void rawBytes() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonGenerator gen = new BsonGenerator(JsonGenerator.Feature.collectDefaults(), 0, baos);
        gen.writeStartObject();
        gen.writeFieldName("Test");
        gen.writeBinary(new byte[] { (byte) 1, (byte) 2 });
        gen.writeEndObject();
        gen.close();

        byte[] r = baos.toByteArray();
        ByteArrayInputStream bais = new ByteArrayInputStream(r);
        BSONDecoder decoder = new BasicBSONDecoder();
        BSONObject obj = decoder.readObject(bais);
        byte[] o = (byte[]) obj.get("Test");
        assertEquals(2, o.length);
        assertEquals((byte) 1, o[0]);
        assertEquals((byte) 2, o[1]);
    }

    @Test
    public void stackedObjects() throws Exception {
        Map<String, Object> data1 = new LinkedHashMap<String, Object>();
        data1.put("Int32", 5);
        Map<String, Object> data3 = new LinkedHashMap<String, Object>();
        data3.put("String", "Hello");

        Map<String, Object> data2 = new LinkedHashMap<String, Object>();
        data2.put("Int64", 10L);
        data2.put("data1", data1);
        data2.put("data3", data3);

        BSONObject obj2 = generateAndParse(data2);

        assertEquals(10L, obj2.get("Int64"));
        BSONObject obj1 = (BSONObject) obj2.get("data1");
        assertEquals(5, obj1.get("Int32"));
        BSONObject obj3 = (BSONObject) obj2.get("data3");
        assertEquals("Hello", obj3.get("String"));
    }

    @Test
    @SuppressWarnings("unchecked")
    public void arrays() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("Int32", 5);
        data.put("Arr", Arrays.asList("a", "b", "c"));
        data.put("Int64", 10L);
        List<String> a3 = Arrays.asList("d", "e", "f");
        List<String> a4 = Arrays.asList("g", "h", "j");
        List<List<String>> a5 = new ArrayList<List<String>>();
        a5.add(a3);
        a5.add(a4);
        data.put("Arr2", a5);

        Map<String, Object> data2 = new LinkedHashMap<String, Object>();
        data2.put("Str", "Hello");
        List<Map<String, Object>> a6 = new ArrayList<Map<String, Object>>();
        a6.add(data2);
        data.put("Arr3", a6);

        BSONObject obj = generateAndParse(data);

        assertEquals(5, obj.get("Int32"));
        List<String> o = (List<String>) obj.get("Arr");
        assertEquals(3, o.size());
        assertEquals("a", o.get(0));
        assertEquals("b", o.get(1));
        assertEquals("c", o.get(2));
        assertEquals(10L, obj.get("Int64"));
        List<List<String>> o5 = (List<List<String>>) obj.get("Arr2");
        assertEquals(a5, o5);
        List<BSONObject> o6 = (List<BSONObject>) obj.get("Arr3");
        assertEquals(1, o6.size());
        BSONObject b6 = o6.get(0);
        assertEquals("Hello", b6.get("Str"));
    }

    @Test
    public void utf8Strings() throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonGenerator gen = new BsonGenerator(JsonGenerator.Feature.collectDefaults(), 0, baos);
        gen.writeStartObject();
        gen.writeFieldName("a\u20AC\u00A2\u00A2bb");
        gen.writeString("a\u20AC\u00A2\u00A2bb");
        gen.writeEndObject();
        gen.close();

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        BSONDecoder decoder = new BasicBSONDecoder();
        BSONObject obj = decoder.readObject(bais);
        String s = (String) obj.get("a\u20AC\u00A2\u00A2bb");
        assertEquals("a\u20AC\u00A2\u00A2bb", s);
    }

    @Test
    public void uuids() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("Int32", 5);
        data.put("Arr", Arrays.asList("a", "b", "c"));
        UUID uuid = UUID.randomUUID();
        data.put("Uuid", uuid);

        BSONObject obj = generateAndParse(data);

        assertEquals(5, obj.get("Int32"));
        assertNotNull(obj.get("Uuid"));
        assertEquals(UUID.class, obj.get("Uuid").getClass());
        assertEquals(uuid, obj.get("Uuid"));
    }

    @Test
    public void dates() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        data.put("date", date);
        data.put("calendar", calendar);

        BSONObject obj = generateAndParse(data);

        assertEquals(date, obj.get("date"));
        assertEquals(date, obj.get("calendar"));
    }

    @Test
    public void objectIds() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        ObjectId objectId = new ObjectId((int) (System.currentTimeMillis() / 1000), new Random().nextInt(), 100);
        data.put("_id", objectId);

        BSONObject obj = generateAndParse(data);

        org.bson.types.ObjectId result = (org.bson.types.ObjectId) obj.get("_id");
        assertNotNull(result);
        assertEquals(objectId.getTime(), result.getTimeSecond());
        assertEquals(objectId.getMachine(), result.getMachine());
        assertEquals(objectId.getInc(), result.getInc());
    }

    @Test
    public void patterns() throws Exception {
        Pattern pattern = Pattern.compile("a.*a", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("pattern", pattern);

        BSONObject obj = generateAndParse(data);

        Pattern result = (Pattern) obj.get("pattern");
        assertNotNull(result);
        assertEquals(pattern.pattern(), result.pattern());
        assertEquals(pattern.flags(), result.flags());
    }

    @Test
    public void timestamps() throws Exception {
        Timestamp timestamp = new Timestamp(100, 200);
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("timestamp", timestamp);

        BSONObject obj = generateAndParse(data);

        BSONTimestamp result = (BSONTimestamp) obj.get("timestamp");
        assertNotNull(result);
        assertEquals(timestamp.getInc(), result.getInc());
        assertEquals(timestamp.getTime(), result.getTime());
    }

    @Test
    public void javascript() throws Exception {
        JavaScript javaScript = new JavaScript("a < 100");
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("javaScript", javaScript);

        BSONObject obj = generateAndParse(data);

        Code result = (Code) obj.get("javaScript");
        assertNotNull(result);
        assertEquals(javaScript.getCode(), result.getCode());
    }

    @Test
    public void javascriptWithScope() throws Exception {
        Map<String, Object> scope = new LinkedHashMap<String, Object>();
        scope.put("a", 99);
        scope.put("b", 80);
        JavaScript javaScript = new JavaScript("a < 100", scope);
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("javaScript", javaScript);

        BSONObject obj = generateAndParse(data);

        CodeWScope result = (CodeWScope) obj.get("javaScript");
        assertNotNull(result);
        assertEquals(javaScript.getCode(), result.getCode());
        Map<?, ?> returnedScope = result.getScope().toMap();
        assertEquals(returnedScope, scope);
    }

    private BSONObject generateAndParse(Map<String, Object> data, BsonGenerator.Feature... featuresToEnable)
            throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonFactory bsonFactory = new BsonFactory();
        if (featuresToEnable != null) {
            for (BsonGenerator.Feature fe : featuresToEnable) {
                bsonFactory.enable(fe);
            }
        }
        ObjectMapper om = new ObjectMapper(bsonFactory);
        om.registerModule(new BsonModule());
        om.writeValue(baos, data);

        byte[] r = baos.toByteArray();
        ByteArrayInputStream bais = new ByteArrayInputStream(r);

        BSONDecoder decoder = new BasicBSONDecoder();
        return decoder.readObject(bais);
    }

    @Test
    public void writeBigDecimalsAsStrings() throws Exception {
        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("big", new BigDecimal("0.3"));

        BSONObject obj = generateAndParse(data);

        Double result = (Double) obj.get("big");

        //BigDecimal("0.3") does not equal 0.3!
        assertEquals(Double.valueOf(0.3), result, 0.000001);
        assertFalse(Double.valueOf(0.3).equals(result));

        data = new LinkedHashMap<String, Object>();
        data.put("big", new BigDecimal("0.3"));

        obj = generateAndParse(data, BsonGenerator.Feature.WRITE_BIGDECIMALS_AS_STRINGS);

        String strResult = (String) obj.get("big");
        assertEquals("0.3", strResult);
    }

    @Test
    public void writeBinaryData() throws Exception {
        byte[] binary = new byte[] { (byte) 0x05, (byte) 0xff, (byte) 0xaf, (byte) 0x30, 'A', 'B', 'C', (byte) 0x13,
                (byte) 0x80, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };

        Map<String, Object> data = new LinkedHashMap<String, Object>();
        data.put("binary", binary);

        //binary data has to be converted to base64 with normal JSON
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = mapper.writeValueAsString(data);
        assertEquals("{\"binary\":\"Bf+vMEFCQxOA/////w==\"}", jsonString);

        //with BSON we don't have to convert to base64
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BsonFactory bsonFactory = new BsonFactory();
        ObjectMapper om = new ObjectMapper(bsonFactory);
        om.writeValue(baos, data);

        //document header (4 bytes) + type (1 byte) + field_name ("binary", 6 bytes) +
        //end_of_string (1 byte) + binary_size (4 bytes) + subtype (1 byte) +
        //binary_data (13 bytes) + end_of_document (1 byte)
        int expectedLen = 4 + 1 + 6 + 1 + 4 + 1 + 13 + 1;

        assertEquals(expectedLen, baos.size());

        //BSON is smaller than JSON (at least in this case)
        assertTrue(baos.size() < jsonString.length());

        //test if binary data can be parsed
        BSONObject obj = generateAndParse(data);
        byte[] objbin = (byte[]) obj.get("binary");
        assertArrayEquals(binary, objbin);
    }
}