Package org.springframework.data.mongodb.core.convert

Source Code of org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests

/*
* Copyright 2013-2014 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 org.hamcrest.CoreMatchers.*;
import static org.hamcrest.collection.IsMapContaining.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;

import java.util.Arrays;
import java.util.List;

import org.hamcrest.Matcher;
import org.hamcrest.collection.IsIterableContainingInOrder;
import org.hamcrest.core.IsEqual;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.DBObjectTestUtils;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.mongodb.DBRef;

/**
* Unit tests for {@link UpdateMapper}.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Thomas Darimont
*/
@RunWith(MockitoJUnitRunner.class)
public class UpdateMapperUnitTests {

  @Mock MongoDbFactory factory;
  MappingMongoConverter converter;
  MongoMappingContext context;
  UpdateMapper mapper;

  private Converter<NestedEntity, DBObject> writingConverterSpy;

  @SuppressWarnings("unchecked")
  @Before
  public void setUp() {

    this.writingConverterSpy = Mockito.spy(new NestedEntityWriteConverter());
    CustomConversions conversions = new CustomConversions(Arrays.asList(writingConverterSpy));

    this.context = new MongoMappingContext();
    this.context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
    this.context.initialize();

    this.converter = new MappingMongoConverter(new DefaultDbRefResolver(factory), context);
    this.converter.setCustomConversions(conversions);
    this.converter.afterPropertiesSet();

    this.mapper = new UpdateMapper(converter);
  }

  /**
   * @see DATAMONGO-721
   */
  @Test
  public void updateMapperRetainsTypeInformationForCollectionField() {

    Update update = new Update().push("list", new ConcreteChildClass("2", "BAR"));

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject push = getAsDBObject(mappedObject, "$push");
    DBObject list = getAsDBObject(push, "aliased");

    assertThat(list.get("_class"), is((Object) ConcreteChildClass.class.getName()));
  }

  /**
   * @see DATAMONGO-807
   */
  @Test
  public void updateMapperShouldRetainTypeInformationForNestedEntities() {

    Update update = Update.update("model", new ModelImpl(1));
    UpdateMapper mapper = new UpdateMapper(converter);

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject set = getAsDBObject(mappedObject, "$set");
    DBObject modelDbObject = (DBObject) set.get("model");
    assertThat(modelDbObject.get("_class"), not(nullValue()));
  }

  /**
   * @see DATAMONGO-807
   */
  @Test
  public void updateMapperShouldNotPersistTypeInformationForKnownSimpleTypes() {

    Update update = Update.update("model.value", 1);
    UpdateMapper mapper = new UpdateMapper(converter);

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject set = getAsDBObject(mappedObject, "$set");
    assertThat(set.get("_class"), nullValue());
  }

  /**
   * @see DATAMONGO-807
   */
  @Test
  public void updateMapperShouldNotPersistTypeInformationForNullValues() {

    Update update = Update.update("model", null);
    UpdateMapper mapper = new UpdateMapper(converter);

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject set = getAsDBObject(mappedObject, "$set");
    assertThat(set.get("_class"), nullValue());
  }

  /**
   * @see DATAMONGO-407
   */
  @Test
  public void updateMapperShouldRetainTypeInformationForNestedCollectionElements() {

    Update update = Update.update("list.$", new ConcreteChildClass("42", "bubu"));

    UpdateMapper mapper = new UpdateMapper(converter);
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject set = getAsDBObject(mappedObject, "$set");
    DBObject modelDbObject = getAsDBObject(set, "aliased.$");
    assertThat(modelDbObject.get("_class"), is((Object) ConcreteChildClass.class.getName()));
  }

  /**
   * @see DATAMONGO-407
   */
  @Test
  public void updateMapperShouldSupportNestedCollectionElementUpdates() {

    Update update = Update.update("list.$.value", "foo").set("list.$.otherValue", "bar");

    UpdateMapper mapper = new UpdateMapper(converter);
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject set = getAsDBObject(mappedObject, "$set");
    assertThat(set.get("aliased.$.value"), is((Object) "foo"));
    assertThat(set.get("aliased.$.otherValue"), is((Object) "bar"));
  }

  /**
   * @see DATAMONGO-407
   */
  @Test
  public void updateMapperShouldWriteTypeInformationForComplexNestedCollectionElementUpdates() {

    Update update = Update.update("list.$.value", "foo").set("list.$.someObject", new ConcreteChildClass("42", "bubu"));

    UpdateMapper mapper = new UpdateMapper(converter);
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject dbo = getAsDBObject(mappedObject, "$set");
    assertThat(dbo.get("aliased.$.value"), is((Object) "foo"));

    DBObject someObject = getAsDBObject(dbo, "aliased.$.someObject");
    assertThat(someObject, is(notNullValue()));
    assertThat(someObject.get("_class"), is((Object) ConcreteChildClass.class.getName()));
    assertThat(someObject.get("value"), is((Object) "bubu"));
  }

  /**
   * @see DATAMONGO-812
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  @Test
  public void updateMapperShouldConvertPushCorrectlyWhenCalledWithEachUsingSimpleTypes() {

    Update update = new Update().push("values").each("spring", "data", "mongodb");
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Model.class));

    DBObject push = getAsDBObject(mappedObject, "$push");
    DBObject values = getAsDBObject(push, "values");
    BasicDBList each = getAsDBList(values, "$each");

    assertThat(push.get("_class"), nullValue());
    assertThat(values.get("_class"), nullValue());

    assertThat(each.toMap(), (Matcher) allOf(hasValue("spring"), hasValue("data"), hasValue("mongodb")));
  }

  /**
   * @see DATAMONGO-812
   */
  @Test
  public void updateMapperShouldConvertPushWhithoutAddingClassInformationWhenUsedWithEvery() {

    Update update = new Update().push("values").each("spring", "data", "mongodb");

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Model.class));
    DBObject push = getAsDBObject(mappedObject, "$push");
    DBObject values = getAsDBObject(push, "values");

    assertThat(push.get("_class"), nullValue());
    assertThat(values.get("_class"), nullValue());
  }

  /**
   * @see DATAMONGO-812
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  @Test
  public void updateMapperShouldConvertPushCorrectlyWhenCalledWithEachUsingCustomTypes() {

    Update update = new Update().push("models").each(new ListModel("spring", "data", "mongodb"));
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject push = getAsDBObject(mappedObject, "$push");
    DBObject model = getAsDBObject(push, "models");
    BasicDBList each = getAsDBList(model, "$each");
    BasicDBList values = getAsDBList((DBObject) each.get(0), "values");

    assertThat(values.toMap(), (Matcher) allOf(hasValue("spring"), hasValue("data"), hasValue("mongodb")));
  }

  /**
   * @see DATAMONGO-812
   */
  @Test
  public void updateMapperShouldRetainClassInformationForPushCorrectlyWhenCalledWithEachUsingCustomTypes() {

    Update update = new Update().push("models").each(new ListModel("spring", "data", "mongodb"));
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject push = getAsDBObject(mappedObject, "$push");
    DBObject model = getAsDBObject(push, "models");
    BasicDBList each = getAsDBList(model, "$each");

    assertThat(((DBObject) each.get(0)).get("_class").toString(), equalTo(ListModel.class.getName()));
  }

  /**
   * @see DATAMONGO-812
   */
  @Test
  public void testUpdateShouldAllowMultiplePushEachForDifferentFields() {

    Update update = new Update().push("category").each("spring", "data").push("type").each("mongodb");
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));

    DBObject push = getAsDBObject(mappedObject, "$push");
    assertThat(getAsDBObject(push, "category").containsField("$each"), is(true));
    assertThat(getAsDBObject(push, "type").containsField("$each"), is(true));
  }

  /**
   * @see DATAMONGO-410
   */
  @Test
  public void testUpdateMapperShouldConsiderCustomWriteTarget() {

    List<NestedEntity> someValues = Arrays.asList(new NestedEntity("spring"), new NestedEntity("data"),
        new NestedEntity("mongodb"));
    NestedEntity[] array = new NestedEntity[someValues.size()];

    Update update = new Update().pushAll("collectionOfNestedEntities", someValues.toArray(array));
    mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(DomainEntity.class));

    verify(writingConverterSpy, times(3)).convert(Mockito.any(NestedEntity.class));
  }

  /**
   * @see DATAMONGO-404
   */
  @Test
  public void createsDbRefForEntityIdOnPulls() {

    Update update = new Update().pull("dbRefAnnotatedList.id", "2");

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithDBRefCollection.class));

    DBObject pullClause = getAsDBObject(mappedObject, "$pull");
    assertThat(pullClause.get("dbRefAnnotatedList"), is((Object) new DBRef(null, "entity", "2")));
  }

  /**
   * @see DATAMONGO-404
   */
  @Test
  public void createsDbRefForEntityOnPulls() {

    Entity entity = new Entity();
    entity.id = "5";

    Update update = new Update().pull("dbRefAnnotatedList", entity);
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithDBRefCollection.class));

    DBObject pullClause = getAsDBObject(mappedObject, "$pull");
    assertThat(pullClause.get("dbRefAnnotatedList"), is((Object) new DBRef(null, "entity", entity.id)));
  }

  /**
   * @see DATAMONGO-404
   */
  @Test(expected = MappingException.class)
  public void rejectsInvalidFieldReferenceForDbRef() {

    Update update = new Update().pull("dbRefAnnotatedList.name", "NAME");
    mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(DocumentWithDBRefCollection.class));
  }

  /**
   * @see DATAMONGO-404
   */
  @Test
  public void rendersNestedDbRefCorrectly() {

    Update update = new Update().pull("nested.dbRefAnnotatedList.id", "2");
    DBObject mappedObject = mapper
        .getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Wrapper.class));

    DBObject pullClause = getAsDBObject(mappedObject, "$pull");
    assertThat(pullClause.containsField("mapped.dbRefAnnotatedList"), is(true));
  }

  /**
   * @see DATAMONGO-468
   */
  @Test
  public void rendersUpdateOfDbRefPropertyWithDomainObjectCorrectly() {

    Entity entity = new Entity();
    entity.id = "5";

    Update update = new Update().set("dbRefProperty", entity);
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithDBRefCollection.class));

    DBObject setClause = getAsDBObject(mappedObject, "$set");
    assertThat(setClause.get("dbRefProperty"), is((Object) new DBRef(null, "entity", entity.id)));
  }

  /**
   * @see DATAMONGO-862
   */
  @Test
  public void rendersUpdateAndPreservesKeyForPathsNotPointingToProperty() {

    Update update = new Update().set("listOfInterface.$.value", "expected-value");
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject setClause = getAsDBObject(mappedObject, "$set");
    assertThat(setClause.containsField("listOfInterface.$.value"), is(true));
  }

  /**
   * @see DATAMONGO-863
   */
  @Test
  public void doesNotConvertRawDbObjects() {

    Update update = new Update();
    update.pull("options",
        new BasicDBObject("_id", new BasicDBObject("$in", converter.convertToMongoType(Arrays.asList(1L, 2L)))));

    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject setClause = getAsDBObject(mappedObject, "$pull");
    DBObject options = getAsDBObject(setClause, "options");
    DBObject idClause = getAsDBObject(options, "_id");
    BasicDBList inClause = getAsDBList(idClause, "$in");

    assertThat(inClause, IsIterableContainingInOrder.<Object> contains(1L, 2L));
  }

  /**
   * @see DATAMONG0-471
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  @Test
  public void testUpdateShouldApply$addToSetCorrectlyWhenUsedWith$each() {

    Update update = new Update().addToSet("values").each("spring", "data", "mongodb");
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ListModel.class));

    DBObject addToSet = getAsDBObject(mappedObject, "$addToSet");
    DBObject values = getAsDBObject(addToSet, "values");
    BasicDBList each = getAsDBList(values, "$each");

    assertThat(each.toMap(), (Matcher) allOf(hasValue("spring"), hasValue("data"), hasValue("mongodb")));
  }

  /**
   * @see DATAMONG0-471
   */
  @Test
  public void testUpdateShouldRetainClassTypeInformationWhenUsing$addToSetWith$eachForCustomTypes() {

    Update update = new Update().addToSet("models").each(new ModelImpl(2014), new ModelImpl(1), new ModelImpl(28));
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ModelWrapper.class));

    DBObject addToSet = getAsDBObject(mappedObject, "$addToSet");

    DBObject values = getAsDBObject(addToSet, "models");
    BasicDBList each = getAsDBList(values, "$each");

    for (Object updateValue : each) {
      assertThat(((DBObject) updateValue).get("_class").toString(),
          equalTo("org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests$ModelImpl"));
    }

  }

  /**
   * @see DATAMONGO-897
   */
  @Test
  public void updateOnDbrefPropertyOfInterfaceTypeWithoutExplicitGetterForIdShouldBeMappedCorrectly() {

    Update update = new Update().set("referencedDocument", new InterfaceDocumentDefinitionImpl("1", "Foo"));
    DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithReferenceToInterfaceImpl.class));

    DBObject $set = DBObjectTestUtils.getAsDBObject(mappedObject, "$set");
    Object model = $set.get("referencedDocument");

    DBRef expectedDBRef = new DBRef(factory.getDb(), "interfaceDocumentDefinitionImpl", "1");
    assertThat(model, allOf(instanceOf(DBRef.class), IsEqual.<Object> equalTo(expectedDBRef)));
  }

  /**
   * @see DATAMONGO-847
   */
  @Test
  public void updateMapperConvertsNestedQueryCorrectly() {

    Update update = new Update().pull("list", Query.query(Criteria.where("value").in("foo", "bar")));
    DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(ParentClass.class));

    DBObject $pull = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$pull");
    DBObject list = DBObjectTestUtils.getAsDBObject($pull, "aliased");
    DBObject value = DBObjectTestUtils.getAsDBObject(list, "value");
    BasicDBList $in = DBObjectTestUtils.getAsDBList(value, "$in");

    assertThat($in, IsIterableContainingInOrder.<Object> contains("foo", "bar"));
  }

  /**
   * @see DATAMONGO-847
   */
  @Test
  public void updateMapperConvertsPullWithNestedQuerfyOnDBRefCorrectly() {

    Update update = new Update().pull("dbRefAnnotatedList", Query.query(Criteria.where("id").is("1")));
    DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithDBRefCollection.class));

    DBObject $pull = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$pull");
    DBObject list = DBObjectTestUtils.getAsDBObject($pull, "dbRefAnnotatedList");

    assertThat(list, equalTo(new BasicDBObjectBuilder().add("_id", "1").get()));
  }

  /**
   * @see DATAMONGO-1077
   */
  @Test
  public void shouldNotRemovePositionalParameter() {

    Update update = new Update();
    update.unset("dbRefAnnotatedList.$");

    DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
        context.getPersistentEntity(DocumentWithDBRefCollection.class));

    DBObject $unset = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$unset");

    assertThat($unset, equalTo(new BasicDBObjectBuilder().add("dbRefAnnotatedList.$", 1).get()));
  }

  @org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface")
  static interface DocumentWithReferenceToInterface {

    String getId();

    InterfaceDocumentDefinitionWithoutId getReferencedDocument();

  }

  static interface InterfaceDocumentDefinitionWithoutId {

    String getValue();
  }

  static class InterfaceDocumentDefinitionImpl implements InterfaceDocumentDefinitionWithoutId {

    @Id String id;
    String value;

    public InterfaceDocumentDefinitionImpl(String id, String value) {

      this.id = id;
      this.value = value;
    }

    @Override
    public String getValue() {
      return this.value;
    }

  }

  static class DocumentWithReferenceToInterfaceImpl implements DocumentWithReferenceToInterface {

    private @Id String id;

    @org.springframework.data.mongodb.core.mapping.DBRef//
    private InterfaceDocumentDefinitionWithoutId referencedDocument;

    public String getId() {
      return id;
    }

    public void setId(String id) {
      this.id = id;
    }

    public void setModel(InterfaceDocumentDefinitionWithoutId referencedDocument) {
      this.referencedDocument = referencedDocument;
    }

    @Override
    public InterfaceDocumentDefinitionWithoutId getReferencedDocument() {
      return this.referencedDocument;
    }

  }

  static interface Model {}

  static class ModelImpl implements Model {
    public int value;

    public ModelImpl(int value) {
      this.value = value;
    }

  }

  public class ModelWrapper {
    Model model;

    public ModelWrapper() {}

    public ModelWrapper(Model model) {
      this.model = model;
    }
  }

  static class ListModelWrapper {

    List<Model> models;
  }

  static class ListModel {

    List<String> values;

    public ListModel(String... values) {
      this.values = Arrays.asList(values);
    }
  }

  static class ParentClass {

    String id;

    @Field("aliased")//
    List<? extends AbstractChildClass> list;

    @Field//
    List<Model> listOfInterface;

    public ParentClass(String id, List<? extends AbstractChildClass> list) {
      this.id = id;
      this.list = list;
    }

  }

  static abstract class AbstractChildClass {

    String id;
    String value;
    String otherValue;
    AbstractChildClass someObject;

    public AbstractChildClass(String id, String value) {
      this.id = id;
      this.value = value;
      this.otherValue = "other_" + value;
    }
  }

  static class ConcreteChildClass extends AbstractChildClass {

    public ConcreteChildClass(String id, String value) {
      super(id, value);
    }
  }

  static class DomainEntity {
    List<NestedEntity> collectionOfNestedEntities;
  }

  static class NestedEntity {
    String name;

    public NestedEntity(String name) {
      super();
      this.name = name;
    }

  }

  @WritingConverter
  static class NestedEntityWriteConverter implements Converter<NestedEntity, DBObject> {

    @Override
    public DBObject convert(NestedEntity source) {
      return new BasicDBObject();
    }
  }

  static class DocumentWithDBRefCollection {

    @Id public String id;

    @org.springframework.data.mongodb.core.mapping.DBRef//
    public List<Entity> dbRefAnnotatedList;

    @org.springframework.data.mongodb.core.mapping.DBRef//
    public Entity dbRefProperty;
  }

  static class Entity {

    @Id public String id;
    String name;
  }

  static class Wrapper {

    @Field("mapped") DocumentWithDBRefCollection nested;
  }
}
TOP

Related Classes of org.springframework.data.mongodb.core.convert.UpdateMapperUnitTests

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.