/*
* Copyright 2011-2017 the original author or authors.
*
* 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 org.springframework.data.mongodb.core.convert;
import static java.time.ZoneId.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.core.DocumentTestUtils.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import org.bson.types.ObjectId;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.geo.Shape;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.MappingInstantiationException;
import org.springframework.data.mongodb.core.DocumentTestUtils;
import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.NestedType;
import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.ProjectingType;
import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTests.ClassWithMapUsingEnumAsKey.FooBarEnum;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.test.util.ReflectionTestUtils;
import com.mongodb.BasicDBList;
import com.mongodb.DBRef;
/**
* Unit tests for {@link MappingMongoConverter}.
*
* @author Oliver Gierke
* @author Patrik Wasik
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class MappingMongoConverterUnitTests {
MappingMongoConverter converter;
MongoMappingContext mappingContext;
@Mock ApplicationContext context;
@Mock DbRefResolver resolver;
public @Rule ExpectedException exception = ExpectedException.none();
@Before
public void setUp() {
mappingContext = new MongoMappingContext();
mappingContext.setApplicationContext(context);
mappingContext.afterPropertiesSet();
mappingContext.getPersistentEntity(Address.class);
converter = new MappingMongoConverter(resolver, mappingContext);
converter.afterPropertiesSet();
}
@Test
public void convertsAddressCorrectly() {
Address address = new Address();
address.city = "New York";
address.street = "Broadway";
org.bson.Document document = new org.bson.Document();
converter.write(address, document);
assertThat(document.get("city").toString(), is("New York"));
assertThat(document.get("street").toString(), is("Broadway"));
}
@Test
public void convertsJodaTimeTypesCorrectly() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.afterPropertiesSet();
Person person = new Person();
person.birthDate = new LocalDate();
org.bson.Document document = new org.bson.Document();
converter.write(person, document);
assertThat(document.get("birthDate"), is(instanceOf(Date.class)));
Person result = converter.read(Person.class, document);
assertThat(result.birthDate, is(notNullValue()));
}
@Test
public void convertsCustomTypeOnConvertToMongoType() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.afterPropertiesSet();
LocalDate date = new LocalDate();
converter.convertToMongoType(date);
}
@Test // DATAMONGO-130
public void writesMapTypeCorrectly() {
Map<Locale, String> map = Collections.singletonMap(Locale.US, "Foo");
org.bson.Document document = new org.bson.Document();
converter.write(map, document);
assertThat(document.get(Locale.US.toString()).toString(), is("Foo"));
}
@Test // DATAMONGO-130
public void readsMapWithCustomKeyTypeCorrectly() {
org.bson.Document mapObject = new org.bson.Document(Locale.US.toString(), "Value");
org.bson.Document document = new org.bson.Document("map", mapObject);
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, document);
assertThat(result.map.get(Locale.US), is("Value"));
}
@Test // DATAMONGO-128
public void usesDocumentsStoredTypeIfSubtypeOfRequest() {
org.bson.Document document = new org.bson.Document();
document.put("birthDate", new LocalDate());
document.put(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Person.class.getName());
assertThat(converter.read(Contact.class, document), is(instanceOf(Person.class)));
}
@Test // DATAMONGO-128
public void ignoresDocumentsStoredTypeIfCompletelyDifferentTypeRequested() {
org.bson.Document document = new org.bson.Document();
document.put("birthDate", new LocalDate());
document.put(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Person.class.getName());
assertThat(converter.read(BirthDateContainer.class, document), is(instanceOf(BirthDateContainer.class)));
}
@Test
public void writesTypeDiscriminatorIntoRootObject() {
Person person = new Person();
org.bson.Document result = new org.bson.Document();
converter.write(person, result);
assertThat(result.containsKey(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY), is(true));
assertThat(result.get(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY).toString(), is(Person.class.getName()));
}
@Test // DATAMONGO-136
public void writesEnumsCorrectly() {
ClassWithEnumProperty value = new ClassWithEnumProperty();
value.sampleEnum = SampleEnum.FIRST;
org.bson.Document result = new org.bson.Document();
converter.write(value, result);
assertThat(result.get("sampleEnum"), is(instanceOf(String.class)));
assertThat(result.get("sampleEnum").toString(), is("FIRST"));
}
@Test // DATAMONGO-209
public void writesEnumCollectionCorrectly() {
ClassWithEnumProperty value = new ClassWithEnumProperty();
value.enums = Arrays.asList(SampleEnum.FIRST);
org.bson.Document result = new org.bson.Document();
converter.write(value, result);
assertThat(result.get("enums"), is(instanceOf(List.class)));
List<Object> enums = (List<Object>) result.get("enums");
assertThat(enums.size(), is(1));
assertThat(enums.get(0), is("FIRST"));
}
@Test // DATAMONGO-136
public void readsEnumsCorrectly() {
org.bson.Document document = new org.bson.Document("sampleEnum", "FIRST");
ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, document);
assertThat(result.sampleEnum, is(SampleEnum.FIRST));
}
@Test // DATAMONGO-209
public void readsEnumCollectionsCorrectly() {
BasicDBList enums = new BasicDBList();
enums.add("FIRST");
org.bson.Document document = new org.bson.Document("enums", enums);
ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, document);
assertThat(result.enums, is(instanceOf(List.class)));
assertThat(result.enums.size(), is(1));
assertThat(result.enums, hasItem(SampleEnum.FIRST));
}
@Test // DATAMONGO-144
public void considersFieldNameWhenWriting() {
Person person = new Person();
person.firstname = "Oliver";
org.bson.Document result = new org.bson.Document();
converter.write(person, result);
assertThat(result.containsKey("foo"), is(true));
assertThat(result.containsKey("firstname"), is(false));
}
@Test // DATAMONGO-144
public void considersFieldNameWhenReading() {
org.bson.Document document = new org.bson.Document("foo", "Oliver");
Person result = converter.read(Person.class, document);
assertThat(result.firstname, is("Oliver"));
}
@Test
public void resolvesNestedComplexTypeForConstructorCorrectly() {
org.bson.Document address = new org.bson.Document("street", "110 Southwark Street");
address.put("city", "London");
BasicDBList addresses = new BasicDBList();
addresses.add(address);
org.bson.Document person = new org.bson.Document("firstname", "Oliver");
person.put("addresses", addresses);
Person result = converter.read(Person.class, person);
assertThat(result.addresses, is(notNullValue()));
}
@Test // DATAMONGO-145
public void writesCollectionWithInterfaceCorrectly() {
Person person = new Person();
person.firstname = "Oliver";
CollectionWrapper wrapper = new CollectionWrapper();
wrapper.contacts = Arrays.asList((Contact) person);
org.bson.Document document = new org.bson.Document();
converter.write(wrapper, document);
Object result = document.get("contacts");
assertThat(result, is(instanceOf(List.class)));
List<Object> contacts = (List<Object>) result;
org.bson.Document personDocument = (org.bson.Document) contacts.get(0);
assertThat(personDocument.get("foo").toString(), is("Oliver"));
assertThat((String) personDocument.get(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY), is(Person.class.getName()));
}
@Test // DATAMONGO-145
public void readsCollectionWithInterfaceCorrectly() {
org.bson.Document person = new org.bson.Document(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Person.class.getName());
person.put("foo", "Oliver");
BasicDBList contacts = new BasicDBList();
contacts.add(person);
CollectionWrapper result = converter.read(CollectionWrapper.class, new org.bson.Document("contacts", contacts));
assertThat(result.contacts, is(notNullValue()));
assertThat(result.contacts.size(), is(1));
Contact contact = result.contacts.get(0);
assertThat(contact, is(instanceOf(Person.class)));
assertThat(((Person) contact).firstname, is("Oliver"));
}
@Test
public void convertsLocalesOutOfTheBox() {
LocaleWrapper wrapper = new LocaleWrapper();
wrapper.locale = Locale.US;
org.bson.Document document = new org.bson.Document();
converter.write(wrapper, document);
Object localeField = document.get("locale");
assertThat(localeField, is(instanceOf(String.class)));
assertThat(localeField, is("en_US"));
LocaleWrapper read = converter.read(LocaleWrapper.class, document);
assertThat(read.locale, is(Locale.US));
}
@Test // DATAMONGO-161
public void readsNestedMapsCorrectly() {
Map<String, String> secondLevel = new HashMap<String, String>();
secondLevel.put("key1", "value1");
secondLevel.put("key2", "value2");
Map<String, Map<String, String>> firstLevel = new HashMap<String, Map<String, String>>();
firstLevel.put("level1", secondLevel);
firstLevel.put("level2", secondLevel);
ClassWithNestedMaps maps = new ClassWithNestedMaps();
maps.nestedMaps = new LinkedHashMap<String, Map<String, Map<String, String>>>();
maps.nestedMaps.put("afield", firstLevel);
org.bson.Document document = new org.bson.Document();
converter.write(maps, document);
ClassWithNestedMaps result = converter.read(ClassWithNestedMaps.class, document);
Map<String, Map<String, Map<String, String>>> nestedMap = result.nestedMaps;
assertThat(nestedMap, is(notNullValue()));
assertThat(nestedMap.get("afield"), is(firstLevel));
}
@Test // DATACMNS-42, DATAMONGO-171
public void writesClassWithBigDecimal() {
BigDecimalContainer container = new BigDecimalContainer();
container.value = BigDecimal.valueOf(2.5d);
container.map = Collections.singletonMap("foo", container.value);
org.bson.Document document = new org.bson.Document();
converter.write(container, document);
assertThat(document.get("value"), is(instanceOf(String.class)));
assertThat((String) document.get("value"), is("2.5"));
assertThat(((org.bson.Document) document.get("map")).get("foo"), is(instanceOf(String.class)));
}
@Test // DATACMNS-42, DATAMONGO-171
public void readsClassWithBigDecimal() {
org.bson.Document document = new org.bson.Document("value", "2.5");
document.put("map", new org.bson.Document("foo", "2.5"));
BasicDBList list = new BasicDBList();
list.add("2.5");
document.put("collection", list);
BigDecimalContainer result = converter.read(BigDecimalContainer.class, document);
assertThat(result.value, is(BigDecimal.valueOf(2.5d)));
assertThat(result.map.get("foo"), is(BigDecimal.valueOf(2.5d)));
assertThat(result.collection.get(0), is(BigDecimal.valueOf(2.5d)));
}
@Test
public void writesNestedCollectionsCorrectly() {
CollectionWrapper wrapper = new CollectionWrapper();
wrapper.strings = Arrays.asList(Arrays.asList("Foo"));
org.bson.Document document = new org.bson.Document();
converter.write(wrapper, document);
Object outerStrings = document.get("strings");
assertThat(outerStrings, is(instanceOf(List.class)));
List<Object> typedOuterString = (List<Object>) outerStrings;
assertThat(typedOuterString.size(), is(1));
}
@Test // DATAMONGO-192
public void readsEmptySetsCorrectly() {
Person person = new Person();
person.addresses = Collections.emptySet();
org.bson.Document document = new org.bson.Document();
converter.write(person, document);
converter.read(Person.class, document);
}
@Test
public void convertsObjectIdStringsToObjectIdCorrectly() {
PersonPojoStringId p1 = new PersonPojoStringId("1234567890", "Text-1");
org.bson.Document doc1 = new org.bson.Document();
converter.write(p1, doc1);
assertThat(doc1.get("_id"), is(instanceOf(String.class)));
PersonPojoStringId p2 = new PersonPojoStringId(new ObjectId().toString(), "Text-1");
org.bson.Document doc2 = new org.bson.Document();
converter.write(p2, doc2);
assertThat(doc2.get("_id"), is(instanceOf(ObjectId.class)));
}
@Test // DATAMONGO-207
public void convertsCustomEmptyMapCorrectly() {
org.bson.Document map = new org.bson.Document();
org.bson.Document wrapper = new org.bson.Document("map", map);
ClassWithSortedMap result = converter.read(ClassWithSortedMap.class, wrapper);
assertThat(result, is(instanceOf(ClassWithSortedMap.class)));
assertThat(result.map, is(instanceOf(SortedMap.class)));
}
@Test // DATAMONGO-211
public void maybeConvertHandlesNullValuesCorrectly() {
assertThat(converter.convertToMongoType(null), is(nullValue()));
}
@Test // DATAMONGO-1509
public void writesGenericTypeCorrectly() {
GenericType<Address> type = new GenericType<Address>();
type.content = new Address();
type.content.city = "London";
org.bson.Document result = new org.bson.Document();
converter.write(type, result);
org.bson.Document content = (org.bson.Document) result.get("content");
assertTypeHint(content, Address.class);
assertThat(content.get("city"), is(notNullValue()));
}
@Test
public void readsGenericTypeCorrectly() {
org.bson.Document address = new org.bson.Document("_class", Address.class.getName());
address.put("city", "London");
GenericType<?> result = converter.read(GenericType.class, new org.bson.Document("content", address));
assertThat(result.content, is(instanceOf(Address.class)));
}
@Test // DATAMONGO-228
public void writesNullValuesForMaps() {
ClassWithMapProperty foo = new ClassWithMapProperty();
foo.map = Collections.singletonMap(Locale.US, null);
org.bson.Document result = new org.bson.Document();
converter.write(foo, result);
Object map = result.get("map");
assertThat(map, is(instanceOf(org.bson.Document.class)));
assertThat(((org.bson.Document) map).keySet(), hasItem("en_US"));
}
@Test
public void writesBigIntegerIdCorrectly() {
ClassWithBigIntegerId foo = new ClassWithBigIntegerId();
foo.id = BigInteger.valueOf(23L);
org.bson.Document result = new org.bson.Document();
converter.write(foo, result);
assertThat(result.get("_id"), is(instanceOf(String.class)));
}
public void convertsObjectsIfNecessary() {
ObjectId id = new ObjectId();
assertThat(converter.convertToMongoType(id), is(id));
}
@Test // DATAMONGO-235
public void writesMapOfListsCorrectly() {
ClassWithMapProperty input = new ClassWithMapProperty();
input.mapOfLists = Collections.singletonMap("Foo", Arrays.asList("Bar"));
org.bson.Document result = new org.bson.Document();
converter.write(input, result);
Object field = result.get("mapOfLists");
assertThat(field, is(instanceOf(org.bson.Document.class)));
org.bson.Document map = (org.bson.Document) field;
Object foo = map.get("Foo");
assertThat(foo, is(instanceOf(List.class)));
List<Object> value = (List<Object>) foo;
assertThat(value.size(), is(1));
assertThat(value.get(0), is("Bar"));
}
@Test // DATAMONGO-235
public void readsMapListValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add("Bar");
org.bson.Document source = new org.bson.Document("mapOfLists", new org.bson.Document("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
assertThat(result.mapOfLists, is(not(nullValue())));
}
@Test // DATAMONGO-235
public void writesMapsOfObjectsCorrectly() {
ClassWithMapProperty input = new ClassWithMapProperty();
input.mapOfObjects = new HashMap<String, Object>();
input.mapOfObjects.put("Foo", Arrays.asList("Bar"));
org.bson.Document result = new org.bson.Document();
converter.write(input, result);
Object field = result.get("mapOfObjects");
assertThat(field, is(instanceOf(org.bson.Document.class)));
org.bson.Document map = (org.bson.Document) field;
Object foo = map.get("Foo");
assertThat(foo, is(instanceOf(BasicDBList.class)));
BasicDBList value = (BasicDBList) foo;
assertThat(value.size(), is(1));
assertThat(value.get(0), is("Bar"));
}
@Test // DATAMONGO-235
public void readsMapOfObjectsListValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add("Bar");
org.bson.Document source = new org.bson.Document("mapOfObjects", new org.bson.Document("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
assertThat(result.mapOfObjects, is(not(nullValue())));
}
@Test // DATAMONGO-245
public void readsMapListNestedValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add(new org.bson.Document("Hello", "World"));
org.bson.Document source = new org.bson.Document("mapOfObjects", new org.bson.Document("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
Object firstObjectInFoo = ((List<?>) result.mapOfObjects.get("Foo")).get(0);
assertThat(firstObjectInFoo, is(instanceOf(Map.class)));
assertThat(((Map<?, ?>) firstObjectInFoo).get("Hello"), is(equalTo("World")));
}
@Test // DATAMONGO-245
public void readsMapDoublyNestedValuesCorrectly() {
org.bson.Document nested = new org.bson.Document();
org.bson.Document doubly = new org.bson.Document();
doubly.append("Hello", "World");
nested.append("nested", doubly);
org.bson.Document source = new org.bson.Document("mapOfObjects", new org.bson.Document("Foo", nested));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
Object foo = result.mapOfObjects.get("Foo");
assertThat(foo, is(instanceOf(Map.class)));
Object doublyNestedObject = ((Map<?, ?>) foo).get("nested");
assertThat(doublyNestedObject, is(instanceOf(Map.class)));
assertThat(((Map<?, ?>) doublyNestedObject).get("Hello"), is(equalTo("World")));
}
@Test // DATAMONGO-245
public void readsMapListDoublyNestedValuesCorrectly() {
BasicDBList list = new BasicDBList();
org.bson.Document nested = new org.bson.Document();
org.bson.Document doubly = new org.bson.Document();
doubly.append("Hello", "World");
nested.append("nested", doubly);
list.add(nested);
org.bson.Document source = new org.bson.Document("mapOfObjects", new org.bson.Document("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
Object firstObjectInFoo = ((List<?>) result.mapOfObjects.get("Foo")).get(0);
assertThat(firstObjectInFoo, is(instanceOf(Map.class)));
Object doublyNestedObject = ((Map<?, ?>) firstObjectInFoo).get("nested");
assertThat(doublyNestedObject, is(instanceOf(Map.class)));
assertThat(((Map<?, ?>) doublyNestedObject).get("Hello"), is(equalTo("World")));
}
@Test // DATAMONGO-259
public void writesListOfMapsCorrectly() {
Map<String, Locale> map = Collections.singletonMap("Foo", Locale.ENGLISH);
CollectionWrapper wrapper = new CollectionWrapper();
wrapper.listOfMaps = new ArrayList<Map<String, Locale>>();
wrapper.listOfMaps.add(map);
org.bson.Document result = new org.bson.Document();
converter.write(wrapper, result);
List<Object> list = (List<Object>) result.get("listOfMaps");
assertThat(list, is(notNullValue()));
assertThat(list.size(), is(1));
org.bson.Document document = (org.bson.Document) list.get(0);
assertThat(document.containsKey("Foo"), is(true));
assertThat((String) document.get("Foo"), is(Locale.ENGLISH.toString()));
}
@Test // DATAMONGO-259
public void readsListOfMapsCorrectly() {
org.bson.Document map = new org.bson.Document("Foo", "en");
BasicDBList list = new BasicDBList();
list.add(map);
org.bson.Document wrapperSource = new org.bson.Document("listOfMaps", list);
CollectionWrapper wrapper = converter.read(CollectionWrapper.class, wrapperSource);
assertThat(wrapper.listOfMaps, is(notNullValue()));
assertThat(wrapper.listOfMaps.size(), is(1));
assertThat(wrapper.listOfMaps.get(0), is(notNullValue()));
assertThat(wrapper.listOfMaps.get(0).get("Foo"), is(Locale.ENGLISH));
}
@Test // DATAMONGO-259
public void writesPlainMapOfCollectionsCorrectly() {
Map<String, List<Locale>> map = Collections.singletonMap("Foo", Arrays.asList(Locale.US));
org.bson.Document result = new org.bson.Document();
converter.write(map, result);
assertThat(result.containsKey("Foo"), is(true));
assertThat(result.get("Foo"), is(notNullValue()));
assertThat(result.get("Foo"), is(instanceOf(BasicDBList.class)));
BasicDBList list = (BasicDBList) result.get("Foo");
assertThat(list.size(), is(1));
assertThat(list.get(0), is(Locale.US.toString()));
}
@Test // DATAMONGO-285
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testSaveMapWithACollectionAsValue() {
Map<String, Object> keyValues = new HashMap<String, Object>();
keyValues.put("string", "hello");
List<String> list = new ArrayList<String>();
list.add("ping");
list.add("pong");
keyValues.put("list", list);
org.bson.Document document = new org.bson.Document();
converter.write(keyValues, document);
Map<String, Object> keyValuesFromMongo = converter.read(Map.class, document);
assertEquals(keyValues.size(), keyValuesFromMongo.size());
assertEquals(keyValues.get("string"), keyValuesFromMongo.get("string"));
assertTrue(List.class.isAssignableFrom(keyValuesFromMongo.get("list").getClass()));
List<String> listFromMongo = (List) keyValuesFromMongo.get("list");
assertEquals(list.size(), listFromMongo.size());
assertEquals(list.get(0), listFromMongo.get(0));
assertEquals(list.get(1), listFromMongo.get(1));
}
@Test // DATAMONGO-309
@SuppressWarnings({ "unchecked" })
public void writesArraysAsMapValuesCorrectly() {
ClassWithMapProperty wrapper = new ClassWithMapProperty();
wrapper.mapOfObjects = new HashMap<String, Object>();
wrapper.mapOfObjects.put("foo", new String[] { "bar" });
org.bson.Document result = new org.bson.Document();
converter.write(wrapper, result);
Object mapObject = result.get("mapOfObjects");
assertThat(mapObject, is(instanceOf(org.bson.Document.class)));
org.bson.Document map = (org.bson.Document) mapObject;
Object valueObject = map.get("foo");
assertThat(valueObject, is(instanceOf(BasicDBList.class)));
List<Object> list = (List<Object>) valueObject;
assertThat(list.size(), is(1));
assertThat(list, hasItem((Object) "bar"));
}
@Test // DATAMONGO-324
public void writesDocumentCorrectly() {
org.bson.Document document = new org.bson.Document();
document.put("foo", "bar");
org.bson.Document result = new org.bson.Document();
converter.write(document, result);
result.remove(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY);
assertThat(document, is(result));
}
@Test // DATAMONGO-324
public void readsDocumentCorrectly() {
org.bson.Document document = new org.bson.Document();
document.put("foo", "bar");
org.bson.Document result = converter.read(org.bson.Document.class, document);
assertThat(result, is(document));
}
@Test // DATAMONGO-329
public void writesMapAsGenericFieldCorrectly() {
Map<String, A<String>> objectToSave = new HashMap<String, A<String>>();
objectToSave.put("test", new A<String>("testValue"));
A<Map<String, A<String>>> a = new A<Map<String, A<String>>>(objectToSave);
org.bson.Document result = new org.bson.Document();
converter.write(a, result);
assertThat(result.get(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY), is(A.class.getName()));
assertThat(result.get("valueType"), is(HashMap.class.getName()));
org.bson.Document object = (org.bson.Document) result.get("value");
assertThat(object, is(notNullValue()));
org.bson.Document inner = (org.bson.Document) object.get("test");
assertThat(inner, is(notNullValue()));
assertThat(inner.get(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY), is(A.class.getName()));
assertThat(inner.get("valueType"), is(String.class.getName()));
assertThat(inner.get("value"), is("testValue"));
}
@Test
public void writesIntIdCorrectly() {
ClassWithIntId value = new ClassWithIntId();
value.id = 5;
org.bson.Document result = new org.bson.Document();
converter.write(value, result);
assertThat(result.get("_id"), is(5));
}
@Test // DATAMONGO-368
@SuppressWarnings("unchecked")
public void writesNullValuesForCollection() {
CollectionWrapper wrapper = new CollectionWrapper();
wrapper.contacts = Arrays.asList(new Person(), null);
org.bson.Document result = new org.bson.Document();
converter.write(wrapper, result);
Object contacts = result.get("contacts");
assertThat(contacts, is(instanceOf(Collection.class)));
assertThat(((Collection<?>) contacts).size(), is(2));
assertThat((Collection<Object>) contacts, hasItem(nullValue()));
}
@Test // DATAMONGO-379
public void considersDefaultingExpressionsAtConstructorArguments() {
org.bson.Document document = new org.bson.Document("foo", "bar");
document.put("foobar", 2.5);
DefaultedConstructorArgument result = converter.read(DefaultedConstructorArgument.class, document);
assertThat(result.bar, is(-1));
}
@Test // DATAMONGO-379
public void usesDocumentFieldIfReferencedInAtValue() {
org.bson.Document document = new org.bson.Document("foo", "bar");
document.put("something", 37);
document.put("foobar", 2.5);
DefaultedConstructorArgument result = converter.read(DefaultedConstructorArgument.class, document);
assertThat(result.bar, is(37));
}
@Test(expected = MappingInstantiationException.class) // DATAMONGO-379
public void rejectsNotFoundConstructorParameterForPrimitiveType() {
org.bson.Document document = new org.bson.Document("foo", "bar");
converter.read(DefaultedConstructorArgument.class, document);
}
@Test // DATAMONGO-358
public void writesListForObjectPropertyCorrectly() {
Attribute attribute = new Attribute();
attribute.key = "key";
attribute.value = Arrays.asList("1", "2");
Item item = new Item();
item.attributes = Arrays.asList(attribute);
org.bson.Document result = new org.bson.Document();
converter.write(item, result);
Item read = converter.read(Item.class, result);
assertThat(read.attributes.size(), is(1));
assertThat(read.attributes.get(0).key, is(attribute.key));
assertThat(read.attributes.get(0).value, is(instanceOf(Collection.class)));
@SuppressWarnings("unchecked")
Collection<String> values = (Collection<String>) read.attributes.get(0).value;
assertThat(values.size(), is(2));
assertThat(values, hasItems("1", "2"));
}
@Test(expected = MappingException.class) // DATAMONGO-380
public void rejectsMapWithKeyContainingDotsByDefault() {
converter.write(Collections.singletonMap("foo.bar", "foobar"), new org.bson.Document());
}
@Test // DATAMONGO-380
public void escapesDotInMapKeysIfReplacementConfigured() {
converter.setMapKeyDotReplacement("~");
org.bson.Document document = new org.bson.Document();
converter.write(Collections.singletonMap("foo.bar", "foobar"), document);
assertThat((String) document.get("foo~bar"), is("foobar"));
assertThat(document.containsKey("foo.bar"), is(false));
}
@Test // DATAMONGO-380
@SuppressWarnings("unchecked")
public void unescapesDotInMapKeysIfReplacementConfigured() {
converter.setMapKeyDotReplacement("~");
org.bson.Document document = new org.bson.Document("foo~bar", "foobar");
Map<String, String> result = converter.read(Map.class, document);
assertThat(result.get("foo.bar"), is("foobar"));
assertThat(result.containsKey("foobar"), is(false));
}
@Test // DATAMONGO-382
@Ignore("mongo3 - no longer supported")
public void convertsSetToBasicDBList() {
Address address = new Address();
address.city = "London";
address.street = "Foo";
Object result = converter.convertToMongoType(Collections.singleton(address), ClassTypeInformation.OBJECT);
assertThat(result, is(instanceOf(List.class)));
Set<?> readResult = converter.read(Set.class, (org.bson.Document) result);
assertThat(readResult.size(), is(1));
assertThat(readResult.iterator().next(), is(instanceOf(Address.class)));
}
@Test // DATAMONGO-402
public void readsMemberClassCorrectly() {
org.bson.Document document = new org.bson.Document("inner", new org.bson.Document("value", "FOO!"));
Outer outer = converter.read(Outer.class, document);
assertThat(outer.inner, is(notNullValue()));
assertThat(outer.inner.value, is("FOO!"));
assertSyntheticFieldValueOf(outer.inner, outer);
}
@Test // DATAMONGO-458
public void readEmptyCollectionIsModifiable() {
org.bson.Document document = new org.bson.Document("contactsSet", new BasicDBList());
CollectionWrapper wrapper = converter.read(CollectionWrapper.class, document);
assertThat(wrapper.contactsSet, is(notNullValue()));
wrapper.contactsSet.add(new Contact() {});
}
@Test // DATAMONGO-424
public void readsPlainDBRefObject() {
DBRef dbRef = new DBRef("foo", 2);
org.bson.Document document = new org.bson.Document("ref", dbRef);
DBRefWrapper result = converter.read(DBRefWrapper.class, document);
assertThat(result.ref, is(dbRef));
}
@Test // DATAMONGO-424
public void readsCollectionOfDBRefs() {
DBRef dbRef = new DBRef("foo", 2);
BasicDBList refs = new BasicDBList();
refs.add(dbRef);
org.bson.Document document = new org.bson.Document("refs", refs);
DBRefWrapper result = converter.read(DBRefWrapper.class, document);
assertThat(result.refs, hasSize(1));
assertThat(result.refs, hasItem(dbRef));
}
@Test // DATAMONGO-424
public void readsDBRefMap() {
DBRef dbRef = mock(DBRef.class);
org.bson.Document refMap = new org.bson.Document("foo", dbRef);
org.bson.Document document = new org.bson.Document("refMap", refMap);
DBRefWrapper result = converter.read(DBRefWrapper.class, document);
assertThat(result.refMap.entrySet(), hasSize(1));
assertThat(result.refMap.values(), hasItem(dbRef));
}
@Test // DATAMONGO-424
@SuppressWarnings({ "rawtypes", "unchecked" })
public void resolvesDBRefMapValue() {
when(resolver.fetch(Mockito.any(DBRef.class))).thenReturn(new org.bson.Document());
DBRef dbRef = mock(DBRef.class);
org.bson.Document refMap = new org.bson.Document("foo", dbRef);
org.bson.Document document = new org.bson.Document("personMap", refMap);
DBRefWrapper result = converter.read(DBRefWrapper.class, document);
Matcher isPerson = instanceOf(Person.class);
assertThat(result.personMap.entrySet(), hasSize(1));
assertThat(result.personMap.values(), hasItem(isPerson));
}
@Test // DATAMONGO-462
public void writesURLsAsStringOutOfTheBox() throws Exception {
URLWrapper wrapper = new URLWrapper();
wrapper.url = new URL("http://springsource.org");
org.bson.Document sink = new org.bson.Document();
converter.write(wrapper, sink);
assertThat(sink.get("url"), is("http://springsource.org"));
}
@Test // DATAMONGO-462
public void readsURLFromStringOutOfTheBox() throws Exception {
org.bson.Document document = new org.bson.Document("url", "http://springsource.org");
URLWrapper result = converter.read(URLWrapper.class, document);
assertThat(result.url, is(new URL("http://springsource.org")));
}
@Test // DATAMONGO-485
public void writesComplexIdCorrectly() {
ComplexId id = new ComplexId();
id.innerId = 4711L;
ClassWithComplexId entity = new ClassWithComplexId();
entity.complexId = id;
org.bson.Document document = new org.bson.Document();
converter.write(entity, document);
Object idField = document.get("_id");
assertThat(idField, is(notNullValue()));
assertThat(idField, is(instanceOf(org.bson.Document.class)));
assertThat(((org.bson.Document) idField).get("innerId"), is(4711L));
}
@Test // DATAMONGO-485
public void readsComplexIdCorrectly() {
org.bson.Document innerId = new org.bson.Document("innerId", 4711L);
org.bson.Document entity = new org.bson.Document("_id", innerId);
ClassWithComplexId result = converter.read(ClassWithComplexId.class, entity);
assertThat(result.complexId, is(notNullValue()));
assertThat(result.complexId.innerId, is(4711L));
}
@Test // DATAMONGO-489
public void readsArraysAsMapValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add("Foo");
list.add("Bar");
org.bson.Document map = new org.bson.Document("key", list);
org.bson.Document wrapper = new org.bson.Document("mapOfStrings", map);
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, wrapper);
assertThat(result.mapOfStrings, is(notNullValue()));
String[] values = result.mapOfStrings.get("key");
assertThat(values, is(notNullValue()));
assertThat(values, is(arrayWithSize(2)));
}
@Test // DATAMONGO-497
public void readsEmptyCollectionIntoConstructorCorrectly() {
org.bson.Document source = new org.bson.Document("attributes", new BasicDBList());
TypWithCollectionConstructor result = converter.read(TypWithCollectionConstructor.class, source);
assertThat(result.attributes, is(notNullValue()));
}
private static void assertSyntheticFieldValueOf(Object target, Object expected) {
for (int i = 0; i < 10; i++) {
try {
assertThat(ReflectionTestUtils.getField(target, "this$" + i), is(expected));
return;
} catch (IllegalArgumentException e) {
// Suppress and try next
}
}
fail(String.format("Didn't find synthetic field on %s!", target));
}
@Test // DATAMGONGO-508
public void eagerlyReturnsDBRefObjectIfTargetAlreadyIsOne() {
DBRef dbRef = new DBRef("collection", "id");
MongoPersistentProperty property = mock(MongoPersistentProperty.class);
assertThat(converter.createDBRef(dbRef, property), is(dbRef));
}
@Test // DATAMONGO-523, DATAMONGO-1509
public void considersTypeAliasAnnotation() {
Aliased aliased = new Aliased();
aliased.name = "foo";
org.bson.Document result = new org.bson.Document();
converter.write(aliased, result);
assertTypeHint(result, "_");
}
@Test // DATAMONGO-533
public void marshalsThrowableCorrectly() {
ThrowableWrapper wrapper = new ThrowableWrapper();
wrapper.throwable = new Exception();
org.bson.Document document = new org.bson.Document();
converter.write(wrapper, document);
}
@Test // DATAMONGO-592
public void recursivelyConvertsSpELReadValue() {
org.bson.Document input = org.bson.Document.parse(
"{ \"_id\" : { \"$oid\" : \"50ca271c4566a2b08f2d667a\" }, \"_class\" : \"com.recorder.TestRecorder2$ObjectContainer\", \"property\" : { \"property\" : 100 } }");
converter.read(ObjectContainer.class, input);
}
@Test // DATAMONGO-724
public void mappingConsidersCustomConvertersNotWritingTypeInformation() {
Person person = new Person();
person.firstname = "Dave";
ClassWithMapProperty entity = new ClassWithMapProperty();
entity.mapOfPersons = new HashMap<String, Person>();
entity.mapOfPersons.put("foo", person);
entity.mapOfObjects = new HashMap<String, Object>();
entity.mapOfObjects.put("foo", person);
CustomConversions conversions = new MongoCustomConversions(
Arrays.asList(new Converter<Person, org.bson.Document>() {
@Override
public org.bson.Document convert(Person source) {
return new org.bson.Document().append("firstname", source.firstname)//
.append("_class", Person.class.getName());
}
}, new Converter<org.bson.Document, Person>() {
@Override
public Person convert(org.bson.Document source) {
Person person = new Person();
person.firstname = source.get("firstname").toString();
person.lastname = "converter";
return person;
}
}));
MongoMappingContext context = new MongoMappingContext();
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
context.afterPropertiesSet();
MappingMongoConverter mongoConverter = new MappingMongoConverter(resolver, context);
mongoConverter.setCustomConversions(conversions);
mongoConverter.afterPropertiesSet();
org.bson.Document document = new org.bson.Document();
mongoConverter.write(entity, document);
ClassWithMapProperty result = mongoConverter.read(ClassWithMapProperty.class, document);
assertThat(result.mapOfPersons, is(notNullValue()));
Person personCandidate = result.mapOfPersons.get("foo");
assertThat(personCandidate, is(notNullValue()));
assertThat(personCandidate.firstname, is("Dave"));
assertThat(result.mapOfObjects, is(notNullValue()));
Object value = result.mapOfObjects.get("foo");
assertThat(value, is(notNullValue()));
assertThat(value, is(instanceOf(Person.class)));
assertThat(((Person) value).firstname, is("Dave"));
assertThat(((Person) value).lastname, is("converter"));
}
@Test // DATAMONGO-743
public void readsIntoStringsOutOfTheBox() {
org.bson.Document document = new org.bson.Document("firstname", "Dave");
assertThat(converter.read(String.class, document), is("{ \"firstname\" : \"Dave\" }"));
}
@Test // DATAMONGO-766
public void writesProjectingTypeCorrectly() {
NestedType nested = new NestedType();
nested.c = "C";
ProjectingType type = new ProjectingType();
type.name = "name";
type.foo = "bar";
type.a = nested;
org.bson.Document result = new org.bson.Document();
converter.write(type, result);
assertThat(result.get("name"), is((Object) "name"));
org.bson.Document aValue = DocumentTestUtils.getAsDocument(result, "a");
assertThat(aValue.get("b"), is((Object) "bar"));
assertThat(aValue.get("c"), is((Object) "C"));
}
@Test // DATAMONGO-812, DATAMONGO-893, DATAMONGO-1509
public void convertsListToBasicDBListAndRetainsTypeInformationForComplexObjects() {
Address address = new Address();
address.city = "London";
address.street = "Foo";
Object result = converter.convertToMongoType(Collections.singletonList(address),
ClassTypeInformation.from(InterfaceType.class));
assertThat(result, is(instanceOf(List.class)));
List<Object> dbList = (List<Object>) result;
assertThat(dbList, hasSize(1));
assertTypeHint(getAsDocument(dbList, 0), Address.class);
}
@Test // DATAMONGO-812
public void convertsListToBasicDBListWithoutTypeInformationForSimpleTypes() {
Object result = converter.convertToMongoType(Collections.singletonList("foo"));
assertThat(result, is(instanceOf(List.class)));
List<Object> dbList = (List<Object>) result;
assertThat(dbList, hasSize(1));
assertThat(dbList.get(0), instanceOf(String.class));
}
@Test // DATAMONGO-812, DATAMONGO-1509
public void convertsArrayToBasicDBListAndRetainsTypeInformationForComplexObjects() {
Address address = new Address();
address.city = "London";
address.street = "Foo";
Object result = converter.convertToMongoType(new Address[] { address }, ClassTypeInformation.OBJECT);
assertThat(result, is(instanceOf(List.class)));
List<Object> dbList = (List<Object>) result;
assertThat(dbList, hasSize(1));
assertTypeHint(getAsDocument(dbList, 0), Address.class);
}
@Test // DATAMONGO-812
public void convertsArrayToBasicDBListWithoutTypeInformationForSimpleTypes() {
Object result = converter.convertToMongoType(new String[] { "foo" });
assertThat(result, is(instanceOf(List.class)));
List<Object> dbList = (List<Object>) result;
assertThat(dbList, hasSize(1));
assertThat(dbList.get(0), instanceOf(String.class));
}
@Test // DATAMONGO-833
public void readsEnumSetCorrectly() {
BasicDBList enumSet = new BasicDBList();
enumSet.add("SECOND");
org.bson.Document document = new org.bson.Document("enumSet", enumSet);
ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, document);
assertThat(result.enumSet, is(instanceOf(EnumSet.class)));
assertThat(result.enumSet.size(), is(1));
assertThat(result.enumSet, hasItem(SampleEnum.SECOND));
}
@Test // DATAMONGO-833
public void readsEnumMapCorrectly() {
org.bson.Document enumMap = new org.bson.Document("FIRST", "Dave");
ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class,
new org.bson.Document("enumMap", enumMap));
assertThat(result.enumMap, is(instanceOf(EnumMap.class)));
assertThat(result.enumMap.size(), is(1));
assertThat(result.enumMap.get(SampleEnum.FIRST), is("Dave"));
}
@Test // DATAMONGO-887
public void readsTreeMapCorrectly() {
org.bson.Document person = new org.bson.Document("foo", "Dave");
org.bson.Document treeMapOfPerson = new org.bson.Document("key", person);
org.bson.Document document = new org.bson.Document("treeMapOfPersons", treeMapOfPerson);
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, document);
assertThat(result.treeMapOfPersons, is(notNullValue()));
assertThat(result.treeMapOfPersons.get("key"), is(notNullValue()));
assertThat(result.treeMapOfPersons.get("key").firstname, is("Dave"));
}
@Test // DATAMONGO-887
public void writesTreeMapCorrectly() {
Person person = new Person();
person.firstname = "Dave";
ClassWithMapProperty source = new ClassWithMapProperty();
source.treeMapOfPersons = new TreeMap<String, Person>();
source.treeMapOfPersons.put("key", person);
org.bson.Document result = new org.bson.Document();
converter.write(source, result);
org.bson.Document map = getAsDocument(result, "treeMapOfPersons");
org.bson.Document entry = getAsDocument(map, "key");
assertThat(entry.get("foo"), is("Dave"));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoBoxCorrectly() {
ClassWithGeoBox object = new ClassWithGeoBox();
object.box = new Box(new Point(1, 2), new Point(3, 4));
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("box"), is(instanceOf(org.bson.Document.class)));
assertThat(document.get("box"), is((Object) new org.bson.Document()
.append("first", toDocument(object.box.getFirst())).append("second", toDocument(object.box.getSecond()))));
}
private static org.bson.Document toDocument(Point point) {
return new org.bson.Document("x", point.getX()).append("y", point.getY());
}
@Test // DATAMONGO-858
public void shouldReadEntityWithGeoBoxCorrectly() {
ClassWithGeoBox object = new ClassWithGeoBox();
object.box = new Box(new Point(1, 2), new Point(3, 4));
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
ClassWithGeoBox result = converter.read(ClassWithGeoBox.class, document);
assertThat(result, is(notNullValue()));
assertThat(result.box, is(object.box));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoPolygonCorrectly() {
ClassWithGeoPolygon object = new ClassWithGeoPolygon();
object.polygon = new Polygon(new Point(1, 2), new Point(3, 4), new Point(4, 5));
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("polygon"), is(instanceOf(org.bson.Document.class)));
org.bson.Document polygonDoc = (org.bson.Document) document.get("polygon");
@SuppressWarnings("unchecked")
List<org.bson.Document> points = (List<org.bson.Document>) polygonDoc.get("points");
assertThat(points, hasSize(3));
assertThat(points, Matchers.<org.bson.Document> hasItems(toDocument(object.polygon.getPoints().get(0)),
toDocument(object.polygon.getPoints().get(1)), toDocument(object.polygon.getPoints().get(2))));
}
@Test // DATAMONGO-858
public void shouldReadEntityWithGeoPolygonCorrectly() {
ClassWithGeoPolygon object = new ClassWithGeoPolygon();
object.polygon = new Polygon(new Point(1, 2), new Point(3, 4), new Point(4, 5));
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
ClassWithGeoPolygon result = converter.read(ClassWithGeoPolygon.class, document);
assertThat(result, is(notNullValue()));
assertThat(result.polygon, is(object.polygon));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoCircleCorrectly() {
ClassWithGeoCircle object = new ClassWithGeoCircle();
Circle circle = new Circle(new Point(1, 2), 3);
Distance radius = circle.getRadius();
object.circle = circle;
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("circle"), is(instanceOf(org.bson.Document.class)));
assertThat(document.get("circle"),
is((Object) new org.bson.Document("center",
new org.bson.Document("x", circle.getCenter().getX()).append("y", circle.getCenter().getY()))
.append("radius", radius.getNormalizedValue()).append("metric", radius.getMetric().toString())));
}
@Test // DATAMONGO-858
public void shouldReadEntityWithGeoCircleCorrectly() {
ClassWithGeoCircle object = new ClassWithGeoCircle();
object.circle = new Circle(new Point(1, 2), 3);
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
ClassWithGeoCircle result = converter.read(ClassWithGeoCircle.class, document);
assertThat(result, is(notNullValue()));
assertThat(result.circle, is(result.circle));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoSphereCorrectly() {
ClassWithGeoSphere object = new ClassWithGeoSphere();
Sphere sphere = new Sphere(new Point(1, 2), 3);
Distance radius = sphere.getRadius();
object.sphere = sphere;
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("sphere"), is(instanceOf(org.bson.Document.class)));
assertThat(document.get("sphere"),
is((Object) new org.bson.Document("center",
new org.bson.Document("x", sphere.getCenter().getX()).append("y", sphere.getCenter().getY()))
.append("radius", radius.getNormalizedValue()).append("metric", radius.getMetric().toString())));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoSphereWithMetricDistanceCorrectly() {
ClassWithGeoSphere object = new ClassWithGeoSphere();
Sphere sphere = new Sphere(new Point(1, 2), new Distance(3, Metrics.KILOMETERS));
Distance radius = sphere.getRadius();
object.sphere = sphere;
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("sphere"), is(instanceOf(org.bson.Document.class)));
assertThat(document.get("sphere"),
is((Object) new org.bson.Document("center",
new org.bson.Document("x", sphere.getCenter().getX()).append("y", sphere.getCenter().getY()))
.append("radius", radius.getNormalizedValue()).append("metric", radius.getMetric().toString())));
}
@Test // DATAMONGO-858
public void shouldReadEntityWithGeoSphereCorrectly() {
ClassWithGeoSphere object = new ClassWithGeoSphere();
object.sphere = new Sphere(new Point(1, 2), 3);
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
ClassWithGeoSphere result = converter.read(ClassWithGeoSphere.class, document);
assertThat(result, is(notNullValue()));
assertThat(result.sphere, is(object.sphere));
}
@Test // DATAMONGO-858
public void shouldWriteEntityWithGeoShapeCorrectly() {
ClassWithGeoShape object = new ClassWithGeoShape();
Sphere sphere = new Sphere(new Point(1, 2), 3);
Distance radius = sphere.getRadius();
object.shape = sphere;
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
assertThat(document, is(notNullValue()));
assertThat(document.get("shape"), is(instanceOf(org.bson.Document.class)));
assertThat(document.get("shape"),
is((Object) new org.bson.Document("center",
new org.bson.Document("x", sphere.getCenter().getX()).append("y", sphere.getCenter().getY()))
.append("radius", radius.getNormalizedValue()).append("metric", radius.getMetric().toString())));
}
@Test // DATAMONGO-858
@Ignore
public void shouldReadEntityWithGeoShapeCorrectly() {
ClassWithGeoShape object = new ClassWithGeoShape();
Sphere sphere = new Sphere(new Point(1, 2), 3);
object.shape = sphere;
org.bson.Document document = new org.bson.Document();
converter.write(object, document);
ClassWithGeoShape result = converter.read(ClassWithGeoShape.class, document);
assertThat(result, is(notNullValue()));
assertThat(result.shape, is(sphere));
}
@Test // DATAMONGO-976
public void shouldIgnoreTextScorePropertyWhenWriting() {
ClassWithTextScoreProperty source = new ClassWithTextScoreProperty();
source.score = Float.MAX_VALUE;
org.bson.Document document = new org.bson.Document();
converter.write(source, document);
assertThat(document.get("score"), nullValue());
}
@Test // DATAMONGO-976
public void shouldIncludeTextScorePropertyWhenReading() {
ClassWithTextScoreProperty entity = converter.read(ClassWithTextScoreProperty.class,
new org.bson.Document("score", 5F));
assertThat(entity.score, equalTo(5F));
}
@Test // DATAMONGO-1001, DATAMONGO-1509
public void shouldWriteCglibProxiedClassTypeInformationCorrectly() {
ProxyFactory factory = new ProxyFactory();
factory.setTargetClass(GenericType.class);
factory.setProxyTargetClass(true);
GenericType<?> proxied = (GenericType<?>) factory.getProxy();
org.bson.Document document = new org.bson.Document();
converter.write(proxied, document);
assertTypeHint(document, GenericType.class);
}
@Test // DATAMONGO-1001
public void shouldUseTargetObjectOfLazyLoadingProxyWhenWriting() {
LazyLoadingProxy mock = mock(LazyLoadingProxy.class);
org.bson.Document document = new org.bson.Document();
converter.write(mock, document);
verify(mock, times(1)).getTarget();
}
@Test // DATAMONGO-1034
public void rejectsBasicDbListToBeConvertedIntoComplexType() {
List<Object> inner = new ArrayList<Object>();
inner.add("key");
inner.add("value");
List<Object> outer = new ArrayList<Object>();
outer.add(inner);
outer.add(inner);
org.bson.Document source = new org.bson.Document("attributes", outer);
exception.expect(MappingException.class);
exception.expectMessage(Item.class.getName());
exception.expectMessage(ArrayList.class.getName());
converter.read(Item.class, source);
}
@Test // DATAMONGO-1058
public void readShouldRespectExplicitFieldNameForDbRef() {
org.bson.Document source = new org.bson.Document();
source.append("explict-name-for-db-ref", new DBRef("foo", "1"));
converter.read(ClassWithExplicitlyNamedDBRefProperty.class, source);
verify(resolver, times(1)).resolveDbRef(Mockito.any(MongoPersistentProperty.class), Mockito.any(DBRef.class),
Mockito.any(DbRefResolverCallback.class), Mockito.any(DbRefProxyHandler.class));
}
@Test // DATAMONGO-1050
public void writeShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() {
RootForClassWithExplicitlyRenamedIdField source = new RootForClassWithExplicitlyRenamedIdField();
source.id = "rootId";
source.nested = new ClassWithExplicitlyRenamedField();
source.nested.id = "nestedId";
org.bson.Document sink = new org.bson.Document();
converter.write(source, sink);
assertThat(sink.get("_id"), is("rootId"));
assertThat(sink.get("nested"), is(new org.bson.Document().append("id", "nestedId")));
}
@Test // DATAMONGO-1050
public void readShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() {
org.bson.Document source = new org.bson.Document().append("_id", "rootId").append("nested",
new org.bson.Document("id", "nestedId"));
RootForClassWithExplicitlyRenamedIdField sink = converter.read(RootForClassWithExplicitlyRenamedIdField.class,
source);
assertThat(sink.id, is("rootId"));
assertThat(sink.nested, notNullValue());
assertThat(sink.nested.id, is("nestedId"));
}
@Test // DATAMONGO-1050
public void namedIdFieldShouldExtractValueFromUnderscoreIdField() {
org.bson.Document document = new org.bson.Document().append("_id", "A").append("id", "B");
ClassWithNamedIdField withNamedIdField = converter.read(ClassWithNamedIdField.class, document);
assertThat(withNamedIdField.id, is("A"));
}
@Test // DATAMONGO-1050
public void explicitlyRenamedIfFieldShouldExtractValueFromIdField() {
org.bson.Document document = new org.bson.Document().append("_id", "A").append("id", "B");
ClassWithExplicitlyRenamedField withExplicitlyRenamedField = converter.read(ClassWithExplicitlyRenamedField.class,
document);
assertThat(withExplicitlyRenamedField.id, is("B"));
}
@Test // DATAMONGO-1050
public void annotatedIdFieldShouldExtractValueFromUnderscoreIdField() {
org.bson.Document document = new org.bson.Document().append("_id", "A").append("id", "B");
ClassWithAnnotatedIdField withAnnotatedIdField = converter.read(ClassWithAnnotatedIdField.class, document);
assertThat(withAnnotatedIdField.key, is("A"));
}
@Test // DATAMONGO-1102
public void convertsJava8DateTimeTypesToDateAndBack() {
TypeWithLocalDateTime source = new TypeWithLocalDateTime();
LocalDateTime reference = source.date;
org.bson.Document result = new org.bson.Document();
converter.write(source, result);
assertThat(result.get("date"), is(instanceOf(Date.class)));
assertThat(converter.read(TypeWithLocalDateTime.class, result).date, is(reference));
}
@Test // DATAMONGO-1128
public void writesOptionalsCorrectly() {
TypeWithOptional type = new TypeWithOptional();
type.localDateTime = Optional.of(LocalDateTime.now());
org.bson.Document result = new org.bson.Document();
converter.write(type, result);
assertThat(getAsDocument(result, "string"), is(new org.bson.Document()));
org.bson.Document localDateTime = getAsDocument(result, "localDateTime");
assertThat(localDateTime.get("value"), is(instanceOf(Date.class)));
}
@Test // DATAMONGO-1128
public void readsOptionalsCorrectly() {
LocalDateTime now = LocalDateTime.now();
Date reference = Date.from(now.atZone(systemDefault()).toInstant());
org.bson.Document optionalOfLocalDateTime = new org.bson.Document("value", reference);
org.bson.Document result = new org.bson.Document("localDateTime", optionalOfLocalDateTime);
TypeWithOptional read = converter.read(TypeWithOptional.class, result);
assertThat(read.string, is(Optional.<String> empty()));
assertThat(read.localDateTime, is(Optional.of(now)));
}
@Test // DATAMONGO-1118
public void convertsMapKeyUsingCustomConverterForAndBackwards() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(
new MongoCustomConversions(Arrays.asList(new FooBarEnumToStringConverter(), new StringToFooNumConverter())));
converter.afterPropertiesSet();
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
source.map = new HashMap<FooBarEnum, String>();
source.map.put(FooBarEnum.FOO, "wohoo");
org.bson.Document target = new org.bson.Document();
converter.write(source, target);
assertThat(converter.read(ClassWithMapUsingEnumAsKey.class, target).map, is(source.map));
}
@Test // DATAMONGO-1118
public void writesMapKeyUsingCustomConverter() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new MongoCustomConversions(Arrays.asList(new FooBarEnumToStringConverter())));
converter.afterPropertiesSet();
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
source.map = new HashMap<FooBarEnum, String>();
source.map.put(FooBarEnum.FOO, "spring");
source.map.put(FooBarEnum.BAR, "data");
org.bson.Document target = new org.bson.Document();
converter.write(source, target);
org.bson.Document map = DocumentTestUtils.getAsDocument(target, "map");
assertThat(map.containsKey("foo-enum-value"), is(true));
assertThat(map.containsKey("bar-enum-value"), is(true));
}
@Test // DATAMONGO-1118
public void readsMapKeyUsingCustomConverter() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new MongoCustomConversions(Arrays.asList(new StringToFooNumConverter())));
converter.afterPropertiesSet();
org.bson.Document source = new org.bson.Document("map", new org.bson.Document("foo-enum-value", "spring"));
ClassWithMapUsingEnumAsKey target = converter.read(ClassWithMapUsingEnumAsKey.class, source);
assertThat(target.map.get(FooBarEnum.FOO), is("spring"));
}
@Test // DATAMONGO-1471
public void readsDocumentWithPrimitiveIdButNoValue() {
assertThat(converter.read(ClassWithIntId.class, new org.bson.Document()), is(notNullValue()));
}
@Test // DATAMONGO-1497
public void readsPropertyFromNestedFieldCorrectly() {
org.bson.Document source = new org.bson.Document("nested", new org.bson.Document("sample", "value"));
TypeWithPropertyInNestedField result = converter.read(TypeWithPropertyInNestedField.class, source);
assertThat(result.sample, is("value"));
}
@Test // DATAMONGO-1525
public void readsEmptyEnumSet() {
org.bson.Document source = new org.bson.Document("enumSet", Collections.emptyList());
assertThat(converter.read(ClassWithEnumProperty.class, source).enumSet, is(EnumSet.noneOf(SampleEnum.class)));
}
static class GenericType<T> {
T content;
}
static class ClassWithEnumProperty {
SampleEnum sampleEnum;
List<SampleEnum> enums;
EnumSet<SampleEnum> enumSet;
EnumMap<SampleEnum, String> enumMap;
}
enum SampleEnum {
FIRST {
@Override
void method() {}
},
SECOND {
@Override
void method() {
}
};
abstract void method();
}
interface InterfaceType {
}
static class Address implements InterfaceType {
String street;
String city;
}
interface Contact {
}
static class Person implements Contact {
@Id String id;
LocalDate birthDate;
@Field("foo") String firstname;
String lastname;
Set<Address> addresses;
public Person() {
}
@PersistenceConstructor
public Person(Set<Address> addresses) {
this.addresses = addresses;
}
}
static class ClassWithSortedMap {
SortedMap<String, String> map;
}
static class ClassWithMapProperty {
Map<Locale, String> map;
Map<String, List<String>> mapOfLists;
Map<String, Object> mapOfObjects;
Map<String, String[]> mapOfStrings;
Map<String, Person> mapOfPersons;
TreeMap<String, Person> treeMapOfPersons;
}
static class ClassWithNestedMaps {
Map<String, Map<String, Map<String, String>>> nestedMaps;
}
static class BirthDateContainer {
LocalDate birthDate;
}
static class BigDecimalContainer {
BigDecimal value;
Map<String, BigDecimal> map;
List<BigDecimal> collection;
}
static class CollectionWrapper {
List<Contact> contacts;
List<List<String>> strings;
List<Map<String, Locale>> listOfMaps;
Set<Contact> contactsSet;
}
static class LocaleWrapper {
Locale locale;
}
static class ClassWithBigIntegerId {
@Id BigInteger id;
}
static class A<T> {
String valueType;
T value;
public A(T value) {
this.valueType = value.getClass().getName();
this.value = value;
}
}
static class ClassWithIntId {
@Id int id;
}
static class DefaultedConstructorArgument {
String foo;
int bar;
double foobar;
DefaultedConstructorArgument(String foo, @Value("#root.something ?: -1") int bar, double foobar) {
this.foo = foo;
this.bar = bar;
this.foobar = foobar;
}
}
static class Item {
List<Attribute> attributes;
}
static class Attribute {
String key;
Object value;
}
static class Outer {
class Inner {
String value;
}
Inner inner;
}
static class DBRefWrapper {
DBRef ref;
List<DBRef> refs;
Map<String, DBRef> refMap;
Map<String, Person> personMap;
}
static class URLWrapper {
URL url;
}
static class ClassWithComplexId {
@Id ComplexId complexId;
}
static class ComplexId {
Long innerId;
}
static class TypWithCollectionConstructor {
List<Attribute> attributes;
public TypWithCollectionConstructor(List<Attribute> attributes) {
this.attributes = attributes;
}
}
@TypeAlias("_")
static class Aliased {
String name;
}
static class ThrowableWrapper {
Throwable throwable;
}
@Document
static class PrimitiveContainer {
@Field("property") private final int m_property;
@PersistenceConstructor
public PrimitiveContainer(@Value("#root.property") int a_property) {
m_property = a_property;
}
public int property() {
return m_property;
}
}
@Document
static class ObjectContainer {
@Field("property") private final PrimitiveContainer m_property;
@PersistenceConstructor
public ObjectContainer(@Value("#root.property") PrimitiveContainer a_property) {
m_property = a_property;
}
public PrimitiveContainer property() {
return m_property;
}
}
class ClassWithGeoBox {
Box box;
}
class ClassWithGeoCircle {
Circle circle;
}
class ClassWithGeoSphere {
Sphere sphere;
}
class ClassWithGeoPolygon {
Polygon polygon;
}
class ClassWithGeoShape {
Shape shape;
}
class ClassWithTextScoreProperty {
@TextScore Float score;
}
class ClassWithExplicitlyNamedDBRefProperty {
@Field("explict-name-for-db-ref") //
@org.springframework.data.mongodb.core.mapping.DBRef //
ClassWithIntId dbRefProperty;
public ClassWithIntId getDbRefProperty() {
return dbRefProperty;
}
}
static class RootForClassWithExplicitlyRenamedIdField {
@Id String id;
ClassWithExplicitlyRenamedField nested;
}
static class ClassWithExplicitlyRenamedField {
@Field("id") String id;
}
static class RootForClassWithNamedIdField {
String id;
ClassWithNamedIdField nested;
}
static class ClassWithNamedIdField {
String id;
}
static class ClassWithAnnotatedIdField {
@Id String key;
}
static class TypeWithLocalDateTime {
LocalDateTime date;
TypeWithLocalDateTime() {
this.date = LocalDateTime.now();
}
}
static class TypeWithOptional {
Optional<String> string = Optional.empty();
Optional<LocalDateTime> localDateTime = Optional.empty();
}
static class ClassWithMapUsingEnumAsKey {
enum FooBarEnum {
FOO, BAR
}
Map<FooBarEnum, String> map;
}
@WritingConverter
static class FooBarEnumToStringConverter implements Converter<FooBarEnum, String> {
@Override
public String convert(FooBarEnum source) {
if (source == null) {
return null;
}
return FooBarEnum.FOO.equals(source) ? "foo-enum-value" : "bar-enum-value";
}
}
@ReadingConverter
static class StringToFooNumConverter implements Converter<String, FooBarEnum> {
@Override
public FooBarEnum convert(String source) {
if (source == null) {
return null;
}
if ("foo-enum-value".equals(source)) {
return FooBarEnum.FOO;
}
if ("bar-enum-value".equals(source)) {
return FooBarEnum.BAR;
}
throw new ConversionNotSupportedException(source, String.class, null);
}
}
static class TypeWithPropertyInNestedField {
@Field("nested.sample") String sample;
}
}