diff --git a/pom.xml b/pom.xml index 50a350594..614dc2ba3 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ 2.0.0.BUILD-SNAPSHOT 3.2.2 1.2.0 + 2.2.17 diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index f3e11c048..f474a5fbe 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.SerializationUtils.*; +import static org.springframework.data.util.Optionals.*; import java.io.IOException; import java.util.*; @@ -94,6 +95,8 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.data.mongodb.util.MongoClientVersion; import org.springframework.data.util.CloseableIterator; +import org.springframework.data.util.Optionals; +import org.springframework.data.util.Pair; import org.springframework.jca.cci.core.ConnectionCallback; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -355,7 +358,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, public CloseableIterator doInCollection(MongoCollection collection) throws MongoException, DataAccessException { - MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(entityType); + MongoPersistentEntity persistentEntity = mappingContext.getRequiredPersistentEntity(entityType); Document mappedFields = queryMapper.getMappedFields(query.getFieldsObject(), persistentEntity); Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), persistentEntity); @@ -441,7 +444,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Assert.notNull(query, "Query must not be null!"); - Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), null); + Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), Optional.empty()); Document sortObject = query.getSortObject(); Document fieldsObject = query.getFieldsObject(); @@ -633,9 +636,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, } public T findById(Object id, Class entityClass, String collectionName) { - MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(entityClass); - MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty(); - String idKey = idProperty == null ? ID_FIELD : idProperty.getName(); + + String idKey = mappingContext.getPersistentEntity(entityClass)// + .flatMap(it -> it.getIdProperty())// + .map(it -> it.getName()).orElse(ID_FIELD); + return doFindOne(collectionName, new Document(idKey, id), null, entityClass); } @@ -755,13 +760,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, final Document document = query == null ? null : queryMapper.getMappedObject(query.getQueryObject(), - entityClass == null ? null : mappingContext.getPersistentEntity(entityClass)); + Optional.ofNullable(entityClass).flatMap(it -> mappingContext.getPersistentEntity(entityClass))); - return execute(collectionName, new CollectionCallback() { - public Long doInCollection(MongoCollection collection) throws MongoException, DataAccessException { - return collection.count(document); - } - }); + return execute(collectionName, (CollectionCallback) collection -> collection.count(document)); } /* @@ -878,13 +879,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, private void initializeVersionProperty(Object entity) { - MongoPersistentEntity mongoPersistentEntity = getPersistentEntity(entity.getClass()); + Optional> persistentEntity = getPersistentEntity(entity.getClass()); - if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) { - ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor( - mongoPersistentEntity.getPropertyAccessor(entity), mongoConverter.getConversionService()); - accessor.setProperty(mongoPersistentEntity.getVersionProperty(), 0); - } + ifAllPresent(persistentEntity, persistentEntity.flatMap(it -> it.getVersionProperty()), (l, r) -> { + ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(l.getPropertyAccessor(entity), + mongoConverter.getConversionService()); + accessor.setProperty(r, Optional.of(0)); + }); } public void insert(Collection batchToSave, Class entityClass) { @@ -909,11 +910,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, continue; } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(element.getClass()); - - if (entity == null) { - throw new InvalidDataAccessApiUsageException("No PersistentEntity information found for " + element.getClass()); - } + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(element.getClass()); String collection = entity.getCollection(); List collectionElements = elementsByCollection.get(collection); @@ -970,35 +967,26 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Assert.notNull(objectToSave, "Object to save must not be null!"); Assert.hasText(collectionName, "Collection name must not be null or empty!"); - MongoPersistentEntity mongoPersistentEntity = getPersistentEntity(objectToSave.getClass()); + Optional> entity = getPersistentEntity(objectToSave.getClass()); + Optional versionProperty = entity.flatMap(it -> it.getVersionProperty()); - // No optimistic locking -> simple save - if (mongoPersistentEntity == null || !mongoPersistentEntity.hasVersionProperty()) { - doSave(collectionName, objectToSave, this.mongoConverter); - return; - } - - doSaveVersioned(objectToSave, mongoPersistentEntity, collectionName); + mapIfAllPresent(entity, versionProperty, // + (l, r) -> doSaveVersioned(objectToSave, l, collectionName))// + .orElseGet(() -> doSave(collectionName, objectToSave, this.mongoConverter)); } - private void doSaveVersioned(T objectToSave, MongoPersistentEntity entity, String collectionName) { + private T doSaveVersioned(T objectToSave, MongoPersistentEntity entity, String collectionName) { ConvertingPropertyAccessor convertingAccessor = new ConvertingPropertyAccessor( entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService()); - MongoPersistentProperty idProperty = entity.getIdProperty(); - MongoPersistentProperty versionProperty = entity.getVersionProperty(); + Optional versionProperty = entity.getVersionProperty(); + Optional versionNumber = versionProperty.flatMap(it -> convertingAccessor.getProperty(it, Number.class)); - Object version = convertingAccessor.getProperty(versionProperty); - Number versionNumber = convertingAccessor.getProperty(versionProperty, Number.class); - - // Fresh instance -> initialize version property - if (version == null) { - doInsert(collectionName, objectToSave, this.mongoConverter); - } else { + return mapIfAllPresent(versionProperty, versionNumber, (property, number) -> { // Bump version number - convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1); + convertingAccessor.setProperty(property, Optional.of(number.longValue() + 1)); maybeEmitEvent(new BeforeConvertEvent(objectToSave, collectionName)); assertUpdateableIdIfNotSet(objectToSave); @@ -1011,8 +999,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Update update = Update.fromDocument(document, ID_FIELD); // Create query for entity with the id and old version - Object id = convertingAccessor.getProperty(idProperty); - Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version)); + MongoPersistentProperty idProperty = entity.getRequiredIdProperty(); + Object id = convertingAccessor.getProperty(idProperty) + .orElseThrow(() -> new IllegalStateException("Required id not found!")); + Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(property.getName()).is(number)); UpdateResult result = doUpdate(collectionName, query, update, objectToSave.getClass(), false, false); @@ -1022,10 +1012,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, versionNumber, collectionName)); } maybeEmitEvent(new AfterSaveEvent(objectToSave, document, collectionName)); - } + + return objectToSave; + + }).orElseGet(() -> { + doInsert(collectionName, objectToSave, this.mongoConverter); + return objectToSave; + }); } - protected void doSave(String collectionName, T objectToSave, MongoWriter writer) { + protected T doSave(String collectionName, T objectToSave, MongoWriter writer) { maybeEmitEvent(new BeforeConvertEvent(objectToSave, collectionName)); assertUpdateableIdIfNotSet(objectToSave); @@ -1037,6 +1033,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, populateIdIfNecessary(objectToSave, id); maybeEmitEvent(new AfterSaveEvent(objectToSave, dbDoc, collectionName)); + + return objectToSave; } protected Object insertDocument(final String collectionName, final Document document, final Class entityClass) { @@ -1174,7 +1172,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, public UpdateResult doInCollection(MongoCollection collection) throws MongoException, DataAccessException { - MongoPersistentEntity entity = entityClass == null ? null : getPersistentEntity(entityClass); + Optional> entity = entityClass == null ? null + : getPersistentEntity(entityClass); increaseVersionForUpdateIfNecessary(entity, update); @@ -1210,23 +1209,23 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, }); } - private void increaseVersionForUpdateIfNecessary(MongoPersistentEntity persistentEntity, Update update) { + private void increaseVersionForUpdateIfNecessary(Optional> persistentEntity, + Update update) { - if (persistentEntity != null && persistentEntity.hasVersionProperty()) { - String versionFieldName = persistentEntity.getVersionProperty().getFieldName(); + ifAllPresent(persistentEntity, persistentEntity.flatMap(it -> it.getVersionProperty()), (entity, property) -> { + String versionFieldName = property.getFieldName(); if (!update.modifies(versionFieldName)) { update.inc(versionFieldName, 1L); } - } + }); } - private boolean documentContainsVersionProperty(Document document, MongoPersistentEntity persistentEntity) { + private boolean documentContainsVersionProperty(Document document, + Optional> persistentEntity) { - if (persistentEntity == null || !persistentEntity.hasVersionProperty()) { - return false; - } - - return document.containsKey(persistentEntity.getVersionProperty().getFieldName()); + return mapIfAllPresent(persistentEntity, persistentEntity.flatMap(it -> it.getVersionProperty()), // + (entity, property) -> document.containsKey(property.getFieldName()))// + .orElse(false); } public DeleteResult remove(Object object) { @@ -1256,25 +1255,21 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, * @param object * @return */ - private Entry extractIdPropertyAndValue(Object object) { + private Pair> extractIdPropertyAndValue(Object object) { Assert.notNull(object, "Id cannot be extracted from 'null'."); Class objectType = object.getClass(); if (object instanceof Document) { - return Collections.singletonMap(ID_FIELD, ((Document) object).get(ID_FIELD)).entrySet().iterator().next(); + return Pair.of(ID_FIELD, Optional.ofNullable(((Document) object).get(ID_FIELD))); } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(objectType); - MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty(); + Optional> entity = mappingContext.getPersistentEntity(objectType); + return mapIfAllPresent(entity, entity.flatMap(it -> it.getIdProperty()), // - if (idProp == null || entity == null) { - throw new MappingException("No id property found for object of type " + objectType); - } - - Object idValue = entity.getPropertyAccessor(object).getProperty(idProp); - return Collections.singletonMap(idProp.getFieldName(), idValue).entrySet().iterator().next(); + (l, r) -> Pair.of(r.getFieldName(), l.getPropertyAccessor(object).getProperty(r)))// + .orElseThrow(() -> new MappingException("No id property found for object of type " + objectType)); } /** @@ -1285,8 +1280,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, */ private Query getIdQueryFor(Object object) { - Entry id = extractIdPropertyAndValue(object); - return new Query(where(id.getKey()).is(id.getValue())); + Pair> id = extractIdPropertyAndValue(object); + return new Query(where(id.getFirst()).is(id.getSecond().orElse(null))); } /** @@ -1300,34 +1295,38 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Assert.notEmpty(objects, "Cannot create Query for empty collection."); Iterator it = objects.iterator(); - Entry firstEntry = extractIdPropertyAndValue(it.next()); + Pair> pair = extractIdPropertyAndValue(it.next()); ArrayList ids = new ArrayList(objects.size()); - ids.add(firstEntry.getValue()); + ids.add(pair.getSecond().orElse(null)); while (it.hasNext()) { - ids.add(extractIdPropertyAndValue(it.next()).getValue()); + ids.add(extractIdPropertyAndValue(it.next()).getSecond().orElse(null)); } - return new Query(where(firstEntry.getKey()).in(ids)); + return new Query(where(pair.getFirst()).in(ids)); } - private void assertUpdateableIdIfNotSet(Object entity) { + private void assertUpdateableIdIfNotSet(Object value) { - MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(entity.getClass()); - MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty(); + Optional> persistentEntity = mappingContext + .getPersistentEntity(value.getClass()); + Optional idProperty = persistentEntity.flatMap(it -> it.getIdProperty()); - if (idProperty == null || persistentEntity == null) { - return; - } + Optionals.ifAllPresent(persistentEntity, idProperty, (entity, property) -> { - Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty); + Optional propertyValue = entity.getPropertyAccessor(value).getProperty(property); - if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) { - throw new InvalidDataAccessApiUsageException( - String.format("Cannot autogenerate id of type %s for entity of type %s!", idProperty.getType().getName(), - entity.getClass().getName())); - } + if (propertyValue.isPresent()) { + return; + } + + if (!MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(property.getType())) { + throw new InvalidDataAccessApiUsageException( + String.format("Cannot autogenerate id of type %s for entity of type %s!", property.getType().getName(), + value.getClass().getName())); + } + }); } public DeleteResult remove(Query query, String collectionName) { @@ -1351,7 +1350,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Assert.hasText(collectionName, "Collection name must not be null or empty!"); final Document queryObject = query.getQueryObject(); - final MongoPersistentEntity entity = getPersistentEntity(entityClass); + final Optional> entity = getPersistentEntity(entityClass); return execute(collectionName, new CollectionCallback() { public DeleteResult doInCollection(MongoCollection collection) @@ -1431,7 +1430,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, result = result.sort(query.getSortObject()); } - result = result.filter(queryMapper.getMappedObject(query.getQueryObject(), null)); + result = result.filter(queryMapper.getMappedObject(query.getQueryObject(), Optional.empty())); } if (mapReduceOptions != null) { @@ -1477,7 +1476,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, if (criteria == null) { document.put("cond", null); } else { - document.put("cond", queryMapper.getMappedObject(criteria.getCriteriaObject(), null)); + document.put("cond", queryMapper.getMappedObject(criteria.getCriteriaObject(), Optional.empty())); } // If initial document was a JavaScript string, potentially loaded by Spring's Resource abstraction, load it and // convert to Document @@ -1853,7 +1852,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, */ protected T doFindOne(String collectionName, Document query, Document fields, Class entityClass) { - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + Optional> entity = mappingContext.getPersistentEntity(entityClass); Document mappedQuery = queryMapper.getMappedObject(query, entity); Document mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity); @@ -1903,7 +1902,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, protected List doFind(String collectionName, Document query, Document fields, Class entityClass, CursorPreparer preparer, DocumentCallback objectCallback) { - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + Optional> entity = mappingContext.getPersistentEntity(entityClass); Document mappedFields = queryMapper.getMappedFields(fields, entity); Document mappedQuery = queryMapper.getMappedObject(query, entity); @@ -1954,7 +1953,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, serializeToJsonSafely(query), fields, sort, entityClass, collectionName); } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + Optional> entity = mappingContext.getPersistentEntity(entityClass); return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort), new ReadDocumentCallback(readerToUse, entityClass, collectionName), collectionName); @@ -1969,7 +1968,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, options = new FindAndModifyOptions(); } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + Optional> entity = mappingContext.getPersistentEntity(entityClass); increaseVersionForUpdateIfNecessary(entity, update); @@ -2005,21 +2004,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return; } - MongoPersistentProperty idProp = getIdPropertyFor(savedObject.getClass()); + getIdPropertyFor(savedObject.getClass()).ifPresent(idProp -> { - if (idProp == null) { - return; - } + ConversionService conversionService = mongoConverter.getConversionService(); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(savedObject.getClass()); + PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject); - ConversionService conversionService = mongoConverter.getConversionService(); - MongoPersistentEntity entity = mappingContext.getPersistentEntity(savedObject.getClass()); - PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject); - - if (accessor.getProperty(idProp) != null) { - return; - } - - new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, id); + Optional value = accessor.getProperty(idProp); + value.ifPresent(it -> new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, value)); + }); } private MongoCollection getAndPrepareCollection(MongoDatabase db, String collectionName) { @@ -2150,13 +2143,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return exceptionTranslator; } - private MongoPersistentEntity getPersistentEntity(Class type) { - return type == null ? null : mappingContext.getPersistentEntity(type); + private Optional> getPersistentEntity(Class type) { + return Optional.ofNullable(type).flatMap(it -> mappingContext.getPersistentEntity(it)); } - private MongoPersistentProperty getIdPropertyFor(Class type) { - MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(type); - return persistentEntity == null ? null : persistentEntity.getIdProperty(); + private Optional getIdPropertyFor(Class type) { + return mappingContext.getPersistentEntity(type).flatMap(it -> it.getIdProperty()); } private String determineEntityCollectionName(T obj) { @@ -2174,12 +2166,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, "No class parameter provided, entity collection can't be determined!"); } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); - if (entity == null) { - throw new InvalidDataAccessApiUsageException( - "No Persistent Entity information found for the class " + entityClass.getName()); - } - return entity.getCollection(); + return mappingContext.getRequiredPersistentEntity(entityClass).getCollection(); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java index ffea59ed5..f29ca67fd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/CustomConversions.java @@ -24,6 +24,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -43,7 +44,6 @@ import org.springframework.data.convert.ThreeTenBackPortConverters; import org.springframework.data.convert.WritingConverter; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes; -import org.springframework.data.util.CacheValue; import org.springframework.util.Assert; /** @@ -71,9 +71,9 @@ public class CustomConversions { private final List converters; - private final Map>> customReadTargetTypes; - private final Map>> customWriteTargetTypes; - private final Map, CacheValue>> rawWriteTargetTypes; + private final Map>> customReadTargetTypes; + private final Map>> customWriteTargetTypes; + private final Map, Optional>> rawWriteTargetTypes; /** * Creates an empty {@link CustomConversions} object. @@ -91,12 +91,12 @@ public class CustomConversions { Assert.notNull(converters, "List of converters must not be null!"); - this.readingPairs = new LinkedHashSet(); - this.writingPairs = new LinkedHashSet(); - this.customSimpleTypes = new HashSet>(); - this.customReadTargetTypes = new ConcurrentHashMap>>(); - this.customWriteTargetTypes = new ConcurrentHashMap>>(); - this.rawWriteTargetTypes = new ConcurrentHashMap, CacheValue>>(); + this.readingPairs = new LinkedHashSet<>(); + this.writingPairs = new LinkedHashSet<>(); + this.customSimpleTypes = new HashSet<>(); + this.customReadTargetTypes = new ConcurrentHashMap<>(); + this.customWriteTargetTypes = new ConcurrentHashMap<>(); + this.rawWriteTargetTypes = new ConcurrentHashMap<>(); List toRegister = new ArrayList(); @@ -241,13 +241,8 @@ public class CustomConversions { */ public Class getCustomWriteTarget(final Class sourceType) { - return getOrCreateAndCache(sourceType, rawWriteTargetTypes, new Producer() { - - @Override - public Class get() { - return getCustomTarget(sourceType, null, writingPairs); - } - }); + return rawWriteTargetTypes.computeIfAbsent(sourceType, it -> getCustomTarget(sourceType, null, writingPairs)) + .orElse(null); } /** @@ -265,14 +260,8 @@ public class CustomConversions { return getCustomWriteTarget(sourceType); } - return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customWriteTargetTypes, - new Producer() { - - @Override - public Class get() { - return getCustomTarget(sourceType, requestedTargetType, writingPairs); - } - }); + return customWriteTargetTypes.computeIfAbsent(new ConvertiblePair(sourceType, requestedTargetType), + it -> getCustomTarget(sourceType, requestedTargetType, writingPairs)).orElse(null); } /** @@ -324,14 +313,8 @@ public class CustomConversions { return null; } - return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customReadTargetTypes, - new Producer() { - - @Override - public Class get() { - return getCustomTarget(sourceType, requestedTargetType, readingPairs); - } - }); + return customReadTargetTypes.computeIfAbsent(new ConvertiblePair(sourceType, requestedTargetType), + it -> getCustomTarget(sourceType, requestedTargetType, readingPairs)).orElse(null); } /** @@ -343,54 +326,26 @@ public class CustomConversions { * @param pairs must not be {@literal null}. * @return */ - private static Class getCustomTarget(Class sourceType, Class requestedTargetType, + private static Optional> getCustomTarget(Class sourceType, Class requestedTargetType, Collection pairs) { Assert.notNull(sourceType, "Source Class must not be null!"); Assert.notNull(pairs, "Collection of ConvertiblePair must not be null!"); if (requestedTargetType != null && pairs.contains(new ConvertiblePair(sourceType, requestedTargetType))) { - return requestedTargetType; + return Optional.of(requestedTargetType); } for (ConvertiblePair typePair : pairs) { if (typePair.getSourceType().isAssignableFrom(sourceType)) { Class targetType = typePair.getTargetType(); if (requestedTargetType == null || targetType.isAssignableFrom(requestedTargetType)) { - return targetType; + return Optional.of(targetType); } } } - return null; - } - - /** - * Will try to find a value for the given key in the given cache or produce one using the given {@link Producer} and - * store it in the cache. - * - * @param key the key to lookup a potentially existing value, must not be {@literal null}. - * @param cache the cache to find the value in, must not be {@literal null}. - * @param producer the {@link Producer} to create values to cache, must not be {@literal null}. - * @return - */ - private static Class getOrCreateAndCache(T key, Map>> cache, Producer producer) { - - CacheValue> cacheValue = cache.get(key); - - if (cacheValue != null) { - return cacheValue.getValue(); - } - - Class type = producer.get(); - cache.put(key, CacheValue.> ofNullable(type)); - - return type; - } - - private interface Producer { - - Class get(); + return Optional.empty(); } @WritingConverter diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java index 6f2838ef4..6e19ef670 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DbRefResolver.java @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.convert; import org.bson.Document; import java.util.List; +import java.util.Optional; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; @@ -45,7 +46,7 @@ public interface DbRefResolver { * @param callback will never be {@literal null}. * @return */ - Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback, + Optional resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback, DbRefProxyHandler proxyHandler); /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java index 1f86a3511..837232cf3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefProxyHandler.java @@ -61,8 +61,9 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler { return proxy; } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(property); - MongoPersistentProperty idProperty = entity.getIdProperty(); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(property); + MongoPersistentProperty idProperty = entity.getIdProperty() + .orElseThrow(() -> new IllegalStateException("Couldn't find identifier property!")); if (idProperty.usePropertyAccess()) { return proxy; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java index 032aaa4d7..175d3cc41 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; @@ -84,17 +85,17 @@ public class DefaultDbRefResolver implements DbRefResolver { * @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback) */ @Override - public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback, + public Optional resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback, DbRefProxyHandler handler) { Assert.notNull(property, "Property must not be null!"); Assert.notNull(callback, "Callback must not be null!"); if (isLazyDbRef(property)) { - return createLazyLoadingProxy(property, dbref, callback, handler); + return Optional.of(createLazyLoadingProxy(property, dbref, callback, handler)); } - return callback.resolve(property); + return Optional.ofNullable(callback.resolve(property)); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java index 2b395c083..3b0f13f82 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.bson.Document; @@ -26,6 +27,7 @@ import org.springframework.data.convert.DefaultTypeMapper; import org.springframework.data.convert.SimpleTypeInformationMapper; import org.springframework.data.convert.TypeAliasAccessor; import org.springframework.data.convert.TypeInformationMapper; +import org.springframework.data.mapping.Alias; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.util.ClassTypeInformation; @@ -116,13 +118,13 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper implements M accessor.writeTypeTo(result, new Document("$in", restrictedMappedTypes)); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.convert.DefaultTypeMapper#getFallbackTypeFor(java.lang.Object) */ @Override - protected TypeInformation getFallbackTypeFor(Bson source) { - - return source instanceof BasicDBList ? LIST_TYPE_INFO : MAP_TYPE_INFO; + protected Optional> getFallbackTypeFor(Bson source) { + return Optional.of(source instanceof BasicDBList ? LIST_TYPE_INFO : MAP_TYPE_INFO); } /** @@ -142,16 +144,16 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper implements M * (non-Javadoc) * @see org.springframework.data.convert.TypeAliasAccessor#readAliasFrom(java.lang.Object) */ - public Object readAliasFrom(Bson source) { + public Alias readAliasFrom(Bson source) { if (source instanceof List) { - return null; + return Alias.NONE; } if (source instanceof Document) { - return ((Document) source).get(typeKey); + return Alias.ofOptional(Optional.ofNullable(((Document) source).get(typeKey))); } else if (source instanceof DBObject) { - return ((DBObject) source).get(typeKey); + return Alias.ofOptional(Optional.ofNullable(((DBObject) source).get(typeKey))); } throw new IllegalArgumentException("Cannot read alias from " + source.getClass()); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java index ac978b15b..58d3adc4d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DocumentAccessor.java @@ -18,6 +18,8 @@ package org.springframework.data.mongodb.core.convert; import java.util.Arrays; import java.util.Iterator; import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; import org.bson.Document; import org.bson.conversions.Bson; @@ -89,6 +91,15 @@ class DocumentAccessor { } } + public void computeIfAbsent(MongoPersistentProperty prop, Supplier> supplier) { + + if (hasValue(prop)) { + return; + } + + supplier.get().ifPresent(it -> put(prop, it)); + } + /** * Returns the value the given {@link MongoPersistentProperty} refers to. By default this will be a direct field but * the method will also transparently resolve nested values the {@link MongoPersistentProperty} might refer to through diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index f7557f30b..d3806909e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -24,6 +24,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import org.bson.Document; @@ -34,7 +35,6 @@ import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.CollectionFactory; -import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.convert.EntityInstantiator; @@ -224,7 +224,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } if (typeToUse.isCollectionLike() && bson instanceof List) { - return (S) readCollectionOrArray(typeToUse, (List) bson, path); + return (S) readCollectionOrArray(typeToUse, (List) bson, path); } if (typeToUse.isMap()) { @@ -239,13 +239,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return (S) bson; } // Retrieve persistent entity info - MongoPersistentEntity persistentEntity = (MongoPersistentEntity) mappingContext - .getPersistentEntity(typeToUse); - if (persistentEntity == null) { - throw new MappingException("No mapping metadata found for " + rawType.getName()); - } - return read(persistentEntity, bson, path); + return read((MongoPersistentEntity) mappingContext.getRequiredPersistentEntity(typeToUse), (Document) bson, + path); } private ParameterValueProvider getParameterProvider(MongoPersistentEntity entity, @@ -259,7 +255,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App path); } - private S read(final MongoPersistentEntity entity, final Bson bson, final ObjectPath path) { + private S read(final MongoPersistentEntity entity, final Document bson, final ObjectPath path) { final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(bson, spELContext); @@ -270,19 +266,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App final PersistentPropertyAccessor accessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(instance), conversionService); - final MongoPersistentProperty idProperty = entity.getIdProperty(); + final Optional idProperty = entity.getIdProperty(); final S result = instance; - - // make sure id property is set before all other properties - Object idValue = null; DocumentAccessor documentAccessor = new DocumentAccessor(bson); - if (idProperty != null && documentAccessor.hasValue(idProperty)) { - idValue = getValueInternal(idProperty, bson, evaluator, path); - accessor.setProperty(idProperty, idValue); - } + // make sure id property is set before all other properties + Object idValue = idProperty.filter(it -> documentAccessor.hasValue(it)).map(it -> { - final ObjectPath currentPath = path.push(result, entity, idValue != null ? documentAccessor.get(idProperty) : null); + Optional value = getValueInternal(it, bson, evaluator, path); + accessor.setProperty(it, value); + + return value; + }); + + final ObjectPath currentPath = path.push(result, entity, + idValue != null ? idProperty.map(it -> bson.get(it.getFieldName())).orElse(null) : null); // Set properties not already set in the constructor entity.doWithProperties(new PropertyHandler() { @@ -364,7 +362,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj; - writeInternal(target, bson, type); + writeInternal(target, bson, Optional.of(type)); if (asMap(bson).containsKey("_is") && asMap(bson).get("_id") == null) { removeFromMap(bson, "_id"); } @@ -382,7 +380,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @param bson */ @SuppressWarnings("unchecked") - protected void writeInternal(final Object obj, final Bson bson, final TypeInformation typeHint) { + protected void writeInternal(final Object obj, final Bson bson, final Optional> typeHint) { if (null == obj) { return; @@ -403,11 +401,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } if (Collection.class.isAssignableFrom(entityType)) { - writeCollectionInternal((Collection) obj, ClassTypeInformation.LIST, (List) bson); + writeCollectionInternal((Collection) obj, Optional.of(ClassTypeInformation.LIST), (BasicDBList) bson); return; } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityType); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(entityType); writeInternal(obj, bson, entity); addCustomTypeKeyIfNecessary(typeHint, obj, bson); } @@ -423,34 +421,28 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(obj); - final MongoPersistentProperty idProperty = entity.getIdProperty(); + DocumentAccessor dbObjectAccessor = new DocumentAccessor(bson); - if (!asMap(bson).containsKey("_id") && null != idProperty) { - - try { - Object id = accessor.getProperty(idProperty); - addToMap(bson, "_id", idMapper.convertId(id)); - } catch (ConversionException ignored) {} - } + Optional idProperty = entity.getIdProperty(); + idProperty.ifPresent( + prop -> dbObjectAccessor.computeIfAbsent(prop, () -> idMapper.convertId(accessor.getProperty(prop)))); // Write the properties entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(MongoPersistentProperty prop) { - if (prop.equals(idProperty) || !prop.isWritable()) { + if (idProperty.map(it -> it.equals(prop)).orElse(false) || !prop.isWritable()) { return; } - Object propertyObj = accessor.getProperty(prop); + accessor.getProperty(prop).ifPresent(it -> { + if (!conversions.isSimpleType(it.getClass())) { - if (null != propertyObj) { - - if (!conversions.isSimpleType(propertyObj.getClass())) { - writePropertyInternal(propertyObj, bson, prop); + writePropertyInternal(it, bson, prop); } else { - writeSimpleInternal(propertyObj, bson, prop); + writeSimpleInternal(it, bson, prop); } - } + }); } }); @@ -459,11 +451,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App public void doWithAssociation(Association association) { MongoPersistentProperty inverseProp = association.getInverse(); - Object propertyObj = accessor.getProperty(inverseProp); - - if (null != propertyObj) { - writePropertyInternal(propertyObj, bson, inverseProp); - } + accessor.getProperty(inverseProp).ifPresent(it -> writePropertyInternal(it, bson, inverseProp)); } }); } @@ -481,7 +469,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App TypeInformation type = prop.getTypeInformation(); if (valueType.isCollectionLike()) { - List collectionInternal = createCollection(asCollection(obj), prop); + List collectionInternal = createCollection(asCollection(obj), prop); accessor.put(prop, collectionInternal); return; } @@ -531,10 +519,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Document document = existingValue instanceof Document ? (Document) existingValue : new Document(); MongoPersistentEntity entity = isSubtype(prop.getType(), obj.getClass()) - ? mappingContext.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type); + ? mappingContext.getRequiredPersistentEntity(obj.getClass()) : mappingContext.getRequiredPersistentEntity(type); writeInternal(obj, document, entity); - addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, document); + addCustomTypeKeyIfNecessary(Optional.of(ClassTypeInformation.from(prop.getRawType())), obj, document); accessor.put(prop, document); } @@ -569,7 +557,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App protected List createCollection(Collection collection, MongoPersistentProperty property) { if (!property.isDbReference()) { - return writeCollectionInternal(collection, property.getTypeInformation(), new ArrayList()); + return writeCollectionInternal(collection, Optional.of(property.getTypeInformation()), new BasicDBList()); } List dbList = new ArrayList(); @@ -631,9 +619,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @param sink the {@link BasicDBList} to write to. * @return */ - private List writeCollectionInternal(Collection source, TypeInformation type, List sink) { + private BasicDBList writeCollectionInternal(Collection source, Optional> type, + BasicDBList sink) { - TypeInformation componentType = type == null ? null : type.getComponentType(); + Optional> componentType = type.flatMap(it -> it.getComponentType()); for (Object element : source) { @@ -678,8 +667,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App writeCollectionInternal(asCollection(val), propertyType.getMapValueType(), new BasicDBList())); } else { Document document = new Document(); - TypeInformation valueTypeInfo = propertyType.isMap() ? propertyType.getMapValueType() - : ClassTypeInformation.OBJECT; + Optional> valueTypeInfo = propertyType.isMap() ? propertyType.getMapValueType() + : Optional.of(ClassTypeInformation.OBJECT); writeInternal(val, document, valueTypeInfo); addToMap(bson, simpleKey, document); } @@ -765,10 +754,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @param value must not be {@literal null}. * @param bson must not be {@literal null}. */ - protected void addCustomTypeKeyIfNecessary(TypeInformation type, Object value, Bson bson) { + protected void addCustomTypeKeyIfNecessary(Optional> type, Object value, Bson bson) { - TypeInformation actualType = type != null ? type.getActualType() : null; - Class reference = actualType == null ? Object.class : actualType.getType(); + Optional> actualType = type.map(it -> it.getActualType()).map(it -> it.getType()); + Class reference = actualType.orElse(Object.class); Class valueType = ClassUtils.getUserClass(value.getClass()); boolean notTheSameClass = !valueType.equals(reference); @@ -857,34 +846,30 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return (DBRef) target; } - MongoPersistentEntity targetEntity = mappingContext.getPersistentEntity(target.getClass()); - targetEntity = targetEntity == null ? targetEntity = mappingContext.getPersistentEntity(property) : targetEntity; + Optional> targetEntity = mappingContext.getPersistentEntity(target.getClass()); + targetEntity = targetEntity.isPresent() ? targetEntity : mappingContext.getPersistentEntity(property); if (null == targetEntity) { throw new MappingException("No mapping metadata found for " + target.getClass()); } - MongoPersistentProperty idProperty = targetEntity.getIdProperty(); + MongoPersistentEntity entity = targetEntity + .orElseThrow(() -> new MappingException("No mapping metadata found for " + target.getClass())); - if (idProperty == null) { - throw new MappingException("No id property found on class " + targetEntity.getType()); - } + Optional idProperty = entity.getIdProperty(); - Object id = null; + return idProperty.map(it -> { - if (target.getClass().equals(idProperty.getType())) { - id = target; - } else { - PersistentPropertyAccessor accessor = targetEntity.getPropertyAccessor(target); - id = accessor.getProperty(idProperty); - } + Object id = target.getClass().equals(it.getType()) ? target : entity.getPropertyAccessor(target).getProperty(it); - if (null == id) { - throw new MappingException("Cannot create a reference to an object with a NULL id."); - } + if (null == id) { + throw new MappingException("Cannot create a reference to an object with a NULL id."); + } - return dbRefResolver.createDbRef(property == null ? null : property.getDBRef(), targetEntity, - idMapper.convertId(id)); + return dbRefResolver.createDbRef(property == null ? null : property.getDBRef(), entity, + idMapper.convertId(Optional.of(id))); + + }).orElseThrow(() -> new MappingException("No id property found on class " + entity.getType())); } /* @@ -892,7 +877,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @see org.springframework.data.mongodb.core.convert.ValueResolver#getValueInternal(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, com.mongodb.Document, org.springframework.data.mapping.model.SpELExpressionEvaluator, java.lang.Object) */ @Override - public Object getValueInternal(MongoPersistentProperty prop, Bson bson, SpELExpressionEvaluator evaluator, + public Optional getValueInternal(MongoPersistentProperty prop, Bson bson, SpELExpressionEvaluator evaluator, ObjectPath path) { return new MongoDbPropertyValueProvider(bson, evaluator, path).getPropertyValue(prop); } @@ -913,8 +898,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Class collectionType = targetType.getType(); - TypeInformation componentType = targetType.getComponentType(); - Class rawComponentType = componentType == null ? null : componentType.getType(); + TypeInformation componentType = targetType.getComponentType().orElse(ClassTypeInformation.OBJECT); + Class rawComponentType = componentType.getType(); collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; Collection items = targetType.getType().isArray() ? new ArrayList() @@ -973,21 +958,20 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Class mapType = typeMapper.readType(bson, type).getType(); - TypeInformation keyType = type.getComponentType(); - Class rawKeyType = keyType == null ? null : keyType.getType(); - - TypeInformation valueType = type.getMapValueType(); - Class rawValueType = valueType == null ? null : valueType.getType(); + Optional> valueType = type.getMapValueType(); + Class rawKeyType = type.getComponentType().map(it -> it.getType()).orElse(null); + Class rawValueType = type.getMapValueType().map(it -> it.getType()).orElse(null); Map sourceMap = asMap(bson); Map map = CollectionFactory.createMap(mapType, rawKeyType, sourceMap.keySet().size()); if (!DBRef.class.equals(rawValueType) && isCollectionOfDbRefWhereBulkFetchIsPossible(sourceMap.values())) { - bulkReadAndConvertDBRefMapIntoTarget(valueType, rawValueType, sourceMap, map); + bulkReadAndConvertDBRefMapIntoTarget(valueType.orElse(null), rawValueType, sourceMap, map); return map; } for (Entry entry : sourceMap.entrySet()) { + if (typeMapper.isTypeKey(entry.getKey())) { continue; } @@ -999,19 +983,19 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } Object value = entry.getValue(); + TypeInformation defaultedValueType = valueType.orElse(ClassTypeInformation.OBJECT); if (value instanceof Document) { - map.put(key, read(valueType, (Document) value, path)); + map.put(key, read(defaultedValueType, (Document) value, path)); } else if (value instanceof BasicDBObject) { - map.put(key, read(valueType, (BasicDBObject) value, path)); + map.put(key, read(defaultedValueType, (BasicDBObject) value, path)); } else if (value instanceof DBRef) { map.put(key, DBRef.class.equals(rawValueType) ? value - : readAndConvertDBRef((DBRef) value, valueType, ObjectPath.ROOT, rawValueType)); + : readAndConvertDBRef((DBRef) value, defaultedValueType, ObjectPath.ROOT, rawValueType)); } else if (value instanceof List) { - map.put(key, readCollectionOrArray(valueType, (List) value, path)); + map.put(key, readCollectionOrArray(valueType.orElse(ClassTypeInformation.LIST), (List) value, path)); } else { - Class valueClass = valueType == null ? null : valueType.getType(); - map.put(key, getPotentiallyConvertedSimpleRead(value, valueClass)); + map.put(key, getPotentiallyConvertedSimpleRead(value, rawValueType)); } } @@ -1043,9 +1027,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App ((DBObject) bson).put(key, value); return; } - throw new IllegalArgumentException( - String.format("Cannot add key/value pair to %s. as map. Given Bson must be a Document or DBObject!", - bson.getClass())); + throw new IllegalArgumentException(String.format( + "Cannot add key/value pair to %s. as map. Given Bson must be a Document or DBObject!", bson.getClass())); } @SuppressWarnings("unchecked") @@ -1061,8 +1044,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return; } - throw new IllegalArgumentException(String.format( - "Cannot add all to %s. Given Bson must be a Document or DBObject.", bson.getClass())); + throw new IllegalArgumentException( + String.format("Cannot add all to %s. Given Bson must be a Document or DBObject.", bson.getClass())); } private void removeFromMap(Bson bson, String key) { @@ -1105,10 +1088,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App TypeInformation typeHint = typeInformation; if (obj instanceof List) { - return maybeConvertList((List) obj, typeHint); + return maybeConvertList((List) obj, typeHint); } if (obj instanceof Document) { + Document newValueDocument = new Document(); for (String vk : ((Document) obj).keySet()) { Object o = ((Document) obj).get(vk); @@ -1118,6 +1102,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } if (obj instanceof DBObject) { + Document newValueDbo = new Document(); for (String vk : ((DBObject) obj).keySet()) { @@ -1130,7 +1115,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App if (obj instanceof Map) { + Map converted = new LinkedHashMap(); Document result = new Document(); + for (Map.Entry entry : ((Map) obj).entrySet()) { result.put(entry.getKey().toString(), convertToMongoType(entry.getValue(), typeHint)); } @@ -1160,9 +1147,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return !obj.getClass().equals(typeInformation.getType()) ? newDocument : removeTypeInfo(newDocument, true); } - public List maybeConvertList(Iterable source, TypeInformation typeInformation) { + public List maybeConvertList(Iterable source, TypeInformation typeInformation) { + + List newDbl = new ArrayList<>(); - List newDbl = new ArrayList(); for (Object element : source) { newDbl.add(convertToMongoType(element, typeInformation)); } @@ -1244,8 +1232,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App */ public MongoDbPropertyValueProvider(Bson source, SpELExpressionEvaluator evaluator, ObjectPath path) { - Assert.notNull(source, "Bson source must not be null!"); + Assert.notNull(source, "Source document must no be null!"); Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null!"); + Assert.notNull(path, "ObjectPath must not be null!"); this.source = new DocumentAccessor(source); this.evaluator = evaluator; @@ -1256,16 +1245,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * (non-Javadoc) * @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty) */ - public T getPropertyValue(MongoPersistentProperty property) { + public Optional getPropertyValue(MongoPersistentProperty property) { + return Optional - String expression = property.getSpelExpression(); - Object value = expression != null ? evaluator.evaluate(expression) : source.get(property); - - if (value == null) { - return null; - } - - return readValue(value, property.getTypeInformation(), path); + .ofNullable(property.getSpelExpression()// + .map(it -> evaluator.evaluate(it))// + .orElseGet(() -> source.get(property)))// + .map(it -> readValue(it, property.getTypeInformation(), path)); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java index e43a9ff04..f7b80ff0b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoExampleMapper.java @@ -40,6 +40,7 @@ import org.springframework.data.mongodb.core.query.MongoRegexCreator; import org.springframework.data.mongodb.core.query.SerializationUtils; import org.springframework.data.repository.core.support.ExampleMatcherAccessor; import org.springframework.data.repository.query.parser.Part.Type; +import org.springframework.data.util.Optionals; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -79,7 +80,7 @@ public class MongoExampleMapper { Assert.notNull(example, "Example must not be null!"); - return getMappedExample(example, mappingContext.getPersistentEntity(example.getProbeType())); + return getMappedExample(example, mappingContext.getRequiredPersistentEntity(example.getProbeType())); } /** @@ -90,7 +91,6 @@ public class MongoExampleMapper { * @param entity must not be {@literal null}. * @return */ - @SuppressWarnings({ "unchecked", "rawtypes" }) public Document getMappedExample(Example example, MongoPersistentEntity entity) { Assert.notNull(example, "Example must not be null!"); @@ -98,9 +98,9 @@ public class MongoExampleMapper { Document reference = (Document) converter.convertToMongoType(example.getProbe()); - if (entity.hasIdProperty() && entity.getIdentifierAccessor(example.getProbe()).getIdentifier() == null) { - reference.remove(entity.getIdProperty().getFieldName()); - } + Optionals.ifAllPresent(entity.getIdProperty(), // + entity.getIdentifierAccessor(example.getProbe()).getIdentifier(), // + (property, identifier) -> reference.remove(property.getFieldName())); ExampleMatcherAccessor matcherAccessor = new ExampleMatcherAccessor(example.getMatcher()); @@ -141,7 +141,7 @@ public class MongoExampleMapper { private String getMappedPropertyPath(String path, Class probeType) { - MongoPersistentEntity entity = mappingContext.getPersistentEntity(probeType); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(probeType); Iterator parts = Arrays.asList(path.split("\\.")).iterator(); @@ -151,39 +151,34 @@ public class MongoExampleMapper { while (parts.hasNext()) { - final String part = parts.next(); - MongoPersistentProperty prop = entity.getPersistentProperty(part); + String part = parts.next(); + MongoPersistentProperty prop = entity.getPersistentProperty(part).orElse(null); if (prop == null) { - entity.doWithProperties(new PropertyHandler() { - - @Override - public void doWithPersistentProperty(MongoPersistentProperty property) { - - if (property.getFieldName().equals(part)) { - stack.push(property); - } + entity.doWithProperties((PropertyHandler) property -> { + if (property.getFieldName().equals(part)) { + stack.push(property); } }); if (stack.isEmpty()) { return ""; } + prop = stack.pop(); } resultParts.add(prop.getName()); if (prop.isEntity() && mappingContext.hasPersistentEntityFor(prop.getActualType())) { - entity = mappingContext.getPersistentEntity(prop.getActualType()); + entity = mappingContext.getRequiredPersistentEntity(prop.getActualType()); } else { break; } } return StringUtils.collectionToDelimitedString(resultParts, "."); - } private void applyPropertySpecs(String path, Document source, Class probeType, diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ObjectPath.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ObjectPath.java index ea1667020..8c583862a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ObjectPath.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ObjectPath.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.util.Assert; @@ -115,8 +116,8 @@ class ObjectPath { * * @return */ - public Object getCurrentObject() { - return items.isEmpty() ? null : items.get(items.size() - 1).getObject(); + public Optional getCurrentObject() { + return items.isEmpty() ? Optional.empty() : Optional.of(items.get(items.size() - 1).getObject()); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index a00b48dde..748ecbec6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import org.bson.BsonValue; @@ -94,6 +95,10 @@ public class QueryMapper { this.exampleMapper = new MongoExampleMapper(converter); } + public Document getMappedObject(Bson query, Optional> entity) { + return getMappedObject(query, entity.orElse(null)); + } + /** * Replaces the property keys used in the given {@link Document} with the appropriate keys by using the * {@link PersistentEntity} metadata. @@ -167,6 +172,10 @@ public class QueryMapper { return mappedSort; } + public Document getMappedSort(Document sortObject, Optional> entity) { + return getMappedSort(sortObject, entity.orElse(null)); + } + /** * Maps fields to retrieve to the {@link MongoPersistentEntity}s properties.
* Also onverts and potentially adds missing property {@code $meta} representation. @@ -183,6 +192,10 @@ public class QueryMapper { return mappedFields.keySet().isEmpty() ? null : mappedFields; } + public Document getMappedFields(Document fieldsObject, Optional> entity) { + return getMappedFields(fieldsObject, entity.orElse(null)); + } + private void mapMetaAttributes(Document source, MongoPersistentEntity entity, MetaMapping metaMapping) { if (entity == null || source == null) { @@ -311,7 +324,7 @@ public class QueryMapper { } else if (valueDbo.containsField("$ne")) { resultDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { - return getMappedObject(resultDbo, null); + return getMappedObject(resultDbo, Optional.empty()); } return resultDbo; } @@ -330,7 +343,7 @@ public class QueryMapper { } else if (valueDbo.containsKey("$ne")) { resultDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { - return getMappedObject(resultDbo, null); + return getMappedObject(resultDbo, Optional.empty()); } return resultDbo; @@ -380,8 +393,8 @@ public class QueryMapper { } MongoPersistentEntity entity = documentField.getPropertyEntity(); - return entity.hasIdProperty() - && (type.equals(DBRef.class) || entity.getIdProperty().getActualType().isAssignableFrom(type)); + return entity.hasIdProperty() && (type.equals(DBRef.class) + || entity.getIdProperty().map(it -> it.getActualType().isAssignableFrom(type)).orElse(false)); } /** @@ -524,28 +537,31 @@ public class QueryMapper { return converter.toDBRef(source, property); } + private Optional convertId(Object id) { + return convertId(Optional.of(id)); + } + /** * Converts the given raw id value into either {@link ObjectId} or {@link String}. * * @param id * @return */ - public Object convertId(Object id) { + public Optional convertId(Optional id) { - if (id == null) { - return null; - } + return id.map(it -> { - if (id instanceof String) { - return ObjectId.isValid(id.toString()) ? conversionService.convert(id, ObjectId.class) : id; - } + if (it instanceof String) { + return ObjectId.isValid(it.toString()) ? conversionService.convert(it, ObjectId.class) : it; + } - try { - return conversionService.canConvert(id.getClass(), ObjectId.class) ? conversionService.convert(id, ObjectId.class) - : delegateConvertToMongoType(id, null); - } catch (ConversionException o_O) { - return delegateConvertToMongoType(id, null); - } + try { + return conversionService.canConvert(it.getClass(), ObjectId.class) + ? conversionService.convert(it, ObjectId.class) : delegateConvertToMongoType(it, null); + } catch (ConversionException o_O) { + return delegateConvertToMongoType(it, null); + } + }); } /** @@ -820,13 +836,9 @@ public class QueryMapper { @Override public boolean isIdField() { - MongoPersistentProperty idProperty = entity.getIdProperty(); - - if (idProperty != null) { - return idProperty.getName().equals(name) || idProperty.getFieldName().equals(name); - } - - return DEFAULT_ID_NAMES.contains(name); + return entity.getIdProperty()// + .map(it -> it.getName().equals(name) || it.getFieldName().equals(name))// + .orElseGet(() -> DEFAULT_ID_NAMES.contains(name)); } /* @@ -845,7 +857,7 @@ public class QueryMapper { @Override public MongoPersistentEntity getPropertyEntity() { MongoPersistentProperty property = getProperty(); - return property == null ? null : mappingContext.getPersistentEntity(property); + return property == null ? null : mappingContext.getRequiredPersistentEntity(property); } /* @@ -875,8 +887,11 @@ public class QueryMapper { if (this.path != null) { for (MongoPersistentProperty p : this.path) { - if (p.isAssociation()) { - return p.getAssociation(); + + Optional> association = p.getAssociation(); + + if (association.isPresent()) { + return association.get(); } } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ValueResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ValueResolver.java index 24a92a7eb..006c18992 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ValueResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ValueResolver.java @@ -15,6 +15,8 @@ */ package org.springframework.data.mongodb.core.convert; +import java.util.Optional; + import org.bson.Document; import org.bson.conversions.Bson; import org.springframework.data.mapping.model.SpELExpressionEvaluator; @@ -38,5 +40,6 @@ interface ValueResolver { * @param parent * @return */ - Object getValueInternal(MongoPersistentProperty prop, Bson bson, SpELExpressionEvaluator evaluator, ObjectPath parent); + Optional getValueInternal(MongoPersistentProperty prop, Bson bson, SpELExpressionEvaluator evaluator, + ObjectPath path); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java index 71734ecc4..6f50d93ac 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java @@ -20,6 +20,7 @@ import java.lang.reflect.Modifier; import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -53,8 +54,8 @@ import org.springframework.util.StringUtils; * @author Christoph Strobl * @author Mark Paluch */ -public class BasicMongoPersistentEntity extends BasicPersistentEntity implements - MongoPersistentEntity, ApplicationContextAware { +public class BasicMongoPersistentEntity extends BasicPersistentEntity + implements MongoPersistentEntity, ApplicationContextAware { private static final String AMBIGUOUS_FIELD_MAPPING = "Ambiguous field mapping detected! Both %s and %s map to the same field name %s! Disambiguate using @Field annotation!"; private static final SpelExpressionParser PARSER = new SpelExpressionParser(); @@ -73,24 +74,18 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity typeInformation) { - super(typeInformation, MongoPersistentPropertyComparator.INSTANCE); + super(typeInformation, Optional.of(MongoPersistentPropertyComparator.INSTANCE)); Class rawType = typeInformation.getType(); String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType); - Document document = this.findAnnotation(Document.class); + Optional document = this.findAnnotation(Document.class); - this.expression = detectExpression(document); + this.expression = document.map(it -> detectExpression(it)).orElse(null); this.context = new StandardEvaluationContext(); - - if (document != null) { - - this.collection = StringUtils.hasText(document.collection()) ? document.collection() : fallback; - this.language = StringUtils.hasText(document.language()) ? document.language() : ""; - } else { - this.collection = fallback; - this.language = ""; - } + this.collection = document.filter(it -> StringUtils.hasText(it.collection())).map(it -> it.collection()) + .orElse(fallback); + this.language = document.filter(it -> StringUtils.hasText(it.language())).map(it -> it.language()).orElse(""); } /* @@ -127,7 +122,7 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity currentIdProperty = getIdProperty(); - boolean currentIdPropertyIsSet = currentIdProperty != null; - @SuppressWarnings("null") - boolean currentIdPropertyIsExplicit = currentIdPropertyIsSet ? currentIdProperty.isExplicitIdProperty() : false; - boolean newIdPropertyIsExplicit = property.isExplicitIdProperty(); + return currentIdProperty.map(it -> { - if (!currentIdPropertyIsSet) { - return property; + boolean currentIdPropertyIsExplicit = it.isExplicitIdProperty(); + boolean newIdPropertyIsExplicit = property.isExplicitIdProperty(); + Optional currentIdPropertyField = it.getField(); - } + if (newIdPropertyIsExplicit && currentIdPropertyIsExplicit) { + throw new MappingException( + String.format( + "Attempt to add explicit id property %s but already have an property %s registered " + + "as explicit id. Check your mapping configuration!", + property.getField(), currentIdPropertyField)); - @SuppressWarnings("null") - Field currentIdPropertyField = currentIdProperty.getField(); + } else if (newIdPropertyIsExplicit && !currentIdPropertyIsExplicit) { + // explicit id property takes precedence over implicit id property + return property; - if (newIdPropertyIsExplicit && currentIdPropertyIsExplicit) { - throw new MappingException(String.format( - "Attempt to add explicit id property %s but already have an property %s registered " - + "as explicit id. Check your mapping configuration!", property.getField(), currentIdPropertyField)); + } else if (!newIdPropertyIsExplicit && currentIdPropertyIsExplicit) { + // no id property override - current property is explicitly defined - } else if (newIdPropertyIsExplicit && !currentIdPropertyIsExplicit) { - // explicit id property takes precedence over implicit id property - return property; + } else { + throw new MappingException( + String.format("Attempt to add id property %s but already have an property %s registered " + + "as id. Check your mapping configuration!", property.getField(), currentIdPropertyField)); + } - } else if (!newIdPropertyIsExplicit && currentIdPropertyIsExplicit) { - // no id property override - current property is explicitly defined + return null; - } else { - throw new MappingException(String.format( - "Attempt to add id property %s but already have an property %s registered " - + "as id. Check your mapping configuration!", property.getField(), currentIdPropertyField)); - } + }).orElse(property); - return null; } /** @@ -274,8 +267,8 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity, - AssociationHandler { + private static class AssertFieldNameUniquenessHandler + implements PropertyHandler, AssociationHandler { private final Map properties = new HashMap(); @@ -293,8 +286,8 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity owner, SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) { + public BasicMongoPersistentProperty(Property property, MongoPersistentEntity owner, + SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) { - super(field, propertyDescriptor, owner, simpleTypeHolder); + super(property, owner, simpleTypeHolder); this.fieldNamingStrategy = fieldNamingStrategy == null ? PropertyNameFieldNamingStrategy.INSTANCE : fieldNamingStrategy; @@ -120,15 +120,11 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope if (isIdProperty()) { - if (owner == null) { + if (!getOwner().getIdProperty().isPresent()) { return ID_FIELD_NAME; } - if (owner.getIdProperty() == null) { - return ID_FIELD_NAME; - } - - if (owner.isIdProperty(this)) { + if (getOwner().isIdProperty(this)) { return ID_FIELD_NAME; } } @@ -158,14 +154,13 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope private String getAnnotatedFieldName() { - org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation( + Optional annotation = findAnnotation( org.springframework.data.mongodb.core.mapping.Field.class); - if (annotation != null && StringUtils.hasText(annotation.value())) { - return annotation.value(); - } - - return null; + return annotation// + .filter(it -> StringUtils.hasText(it.value()))// + .map(it -> it.value())// + .orElse(null); } /* @@ -173,9 +168,11 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder() */ public int getFieldOrder() { - org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation( + + Optional annotation = findAnnotation( org.springframework.data.mongodb.core.mapping.Field.class); - return annotation != null ? annotation.order() : Integer.MAX_VALUE; + + return annotation.map(it -> it.order()).orElse(Integer.MAX_VALUE); } /* @@ -200,7 +197,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getDBRef() */ public DBRef getDBRef() { - return findAnnotation(DBRef.class); + return findAnnotation(DBRef.class).orElse(null); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java index e9389162b..e91435347 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/CachingMongoPersistentProperty.java @@ -15,10 +15,8 @@ */ package org.springframework.data.mongodb.core.mapping; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; - import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.SimpleTypeHolder; /** @@ -43,9 +41,9 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty * @param simpleTypeHolder * @param fieldNamingStrategy */ - public CachingMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, - MongoPersistentEntity owner, SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) { - super(field, propertyDescriptor, owner, simpleTypeHolder, fieldNamingStrategy); + public CachingMongoPersistentProperty(Property property, MongoPersistentEntity owner, + SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) { + super(property, owner, simpleTypeHolder, fieldNamingStrategy); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EntityHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EntityHandler.java new file mode 100644 index 000000000..21c05a9dd --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EntityHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2016 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.mapping; + +import lombok.Value; + +import java.util.Optional; +import java.util.function.BiConsumer; + +import org.springframework.data.util.Optionals; + +/** + * @author Oliver Gierke + */ +@Value(staticConstructor = "of") +public class EntityHandler> { + + Optional entity; + + public void doWithVersionProperty(BiConsumer consumer) { + + Optionals.ifAllPresent(entity, entity.flatMap(it -> it.getVersionProperty()), consumer); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java index c87806285..e9c21bac0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.core.mapping; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; import java.util.AbstractMap; import org.springframework.beans.BeansException; @@ -25,6 +23,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.data.mapping.context.AbstractMappingContext; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; @@ -76,9 +75,9 @@ public class MongoMappingContext extends AbstractMappingContext owner, SimpleTypeHolder simpleTypeHolder) { - return new CachingMongoPersistentProperty(field, descriptor, owner, simpleTypeHolder, fieldNamingStrategy); + public MongoPersistentProperty createPersistentProperty(Property property, BasicMongoPersistentEntity owner, + SimpleTypeHolder simpleTypeHolder) { + return new CachingMongoPersistentProperty(property, owner, simpleTypeHolder, fieldNamingStrategy); } /* diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DocumentAccessorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DocumentAccessorUnitTests.java index 36e825a53..6b31f7726 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DocumentAccessorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DocumentAccessorUnitTests.java @@ -18,7 +18,6 @@ package org.springframework.data.mongodb.core.convert; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; -import com.mongodb.BasicDBObject; import org.bson.BsonDocument; import org.bson.Document; import org.junit.Test; @@ -28,6 +27,8 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import com.mongodb.BasicDBObject; + /** * Unit tests for {@link DocumentAccessor}. * @@ -36,8 +37,8 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; public class DocumentAccessorUnitTests { MongoMappingContext context = new MongoMappingContext(); - MongoPersistentEntity projectingTypeEntity = context.getPersistentEntity(ProjectingType.class); - MongoPersistentProperty fooProperty = projectingTypeEntity.getPersistentProperty("foo"); + MongoPersistentEntity projectingTypeEntity = context.getRequiredPersistentEntity(ProjectingType.class); + MongoPersistentProperty fooProperty = projectingTypeEntity.getRequiredPersistentProperty("foo"); @Test // DATAMONGO-766 public void putsNestedFieldCorrectly() { @@ -80,14 +81,14 @@ public class DocumentAccessorUnitTests { @Test // DATAMONGO-1335 public void writesAllNestingsCorrectly() { - MongoPersistentEntity entity = context.getPersistentEntity(TypeWithTwoNestings.class); + MongoPersistentEntity entity = context.getRequiredPersistentEntity(TypeWithTwoNestings.class); Document target = new Document(); DocumentAccessor accessor = new DocumentAccessor(target); - accessor.put(entity.getPersistentProperty("id"), "id"); - accessor.put(entity.getPersistentProperty("b"), "b"); - accessor.put(entity.getPersistentProperty("c"), "c"); + accessor.put(entity.getRequiredPersistentProperty("id"), "id"); + accessor.put(entity.getRequiredPersistentProperty("b"), "b"); + accessor.put(entity.getRequiredPersistentProperty("c"), "c"); Document nestedA = DocumentTestUtils.getAsDocument(target, "a"); @@ -100,11 +101,11 @@ public class DocumentAccessorUnitTests { public void exposesAvailabilityOfFields() { DocumentAccessor accessor = new DocumentAccessor(new Document("a", new BasicDBObject("c", "d"))); - MongoPersistentEntity entity = context.getPersistentEntity(ProjectingType.class); + MongoPersistentEntity entity = context.getRequiredPersistentEntity(ProjectingType.class); - assertThat(accessor.hasValue(entity.getPersistentProperty("foo")), is(false)); - assertThat(accessor.hasValue(entity.getPersistentProperty("a")), is(true)); - assertThat(accessor.hasValue(entity.getPersistentProperty("name")), is(false)); + assertThat(accessor.hasValue(entity.getRequiredPersistentProperty("foo")), is(false)); + assertThat(accessor.hasValue(entity.getRequiredPersistentProperty("a")), is(true)); + assertThat(accessor.hasValue(entity.getRequiredPersistentProperty("name")), is(false)); } static class ProjectingType { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index f43548e6f..b1ce94b6e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -115,6 +115,8 @@ public class MappingMongoConverterUnitTests { mappingContext.setApplicationContext(context); mappingContext.afterPropertiesSet(); + mappingContext.getPersistentEntity(Address.class); + converter = new MappingMongoConverter(resolver, mappingContext); converter.afterPropertiesSet(); } @@ -413,7 +415,6 @@ public class MappingMongoConverterUnitTests { } @Test - @SuppressWarnings("unchecked") public void writesNestedCollectionsCorrectly() { CollectionWrapper wrapper = new CollectionWrapper(); @@ -495,7 +496,6 @@ public class MappingMongoConverterUnitTests { GenericType result = converter.read(GenericType.class, new org.bson.Document("content", address)); assertThat(result.content, is(instanceOf(Address.class))); - } @Test // DATAMONGO-228 @@ -1134,7 +1134,6 @@ public class MappingMongoConverterUnitTests { } @Test // DATAMONGO-724 - @SuppressWarnings("unchecked") public void mappingConsidersCustomConvertersNotWritingTypeInformation() { Person person = new Person(); @@ -1345,8 +1344,8 @@ public class MappingMongoConverterUnitTests { 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())))); + 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) { @@ -1386,7 +1385,7 @@ public class MappingMongoConverterUnitTests { List points = (List) polygonDoc.get("points"); assertThat(points, hasSize(3)); - assertThat(points, Matchers. hasItems(toDocument(object.polygon.getPoints().get(0)), + assertThat(points, Matchers.hasItems(toDocument(object.polygon.getPoints().get(0)), toDocument(object.polygon.getPoints().get(1)), toDocument(object.polygon.getPoints().get(2)))); } @@ -1705,12 +1704,11 @@ public class MappingMongoConverterUnitTests { TypeWithOptional read = converter.read(TypeWithOptional.class, result); - assertThat(read.string, is(Optional. empty())); + assertThat(read.string, is(Optional.empty())); assertThat(read.localDateTime, is(Optional.of(now))); } @Test // DATAMONGO-1118 - @SuppressWarnings("unchecked") public void convertsMapKeyUsingCustomConverterForAndBackwards() { MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java index 815cd0c8c..cf9c12603 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java @@ -80,7 +80,8 @@ public class MongoExampleMapperUnitTests { IsBsonObject expected = isBsonObject().containing("_id", "steelheart"); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(FlatDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -96,7 +97,8 @@ public class MongoExampleMapperUnitTests { containing("stringValue", "firefight").// containing("intValue", 100); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(FlatDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -110,7 +112,8 @@ public class MongoExampleMapperUnitTests { containing("stringValue", "firefight").// containing("intValue", 100); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(FlatDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -124,7 +127,8 @@ public class MongoExampleMapperUnitTests { IsBsonObject expected = isBsonObject().// containing("listOfString", list); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(FlatDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -135,7 +139,8 @@ public class MongoExampleMapperUnitTests { IsBsonObject expected = isBsonObject().containing("custom_field_name", "Mitosis"); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(FlatDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -146,7 +151,7 @@ public class MongoExampleMapperUnitTests { probe.flatDoc.stringValue = "conflux"; org.bson.Document document = mapper.getMappedExample(Example.of(probe), - context.getPersistentEntity(WrapperDocument.class)); + context.getRequiredPersistentEntity(WrapperDocument.class)); assertThat(document, isBsonObject().containing("_class", new org.bson.Document("$in", new String[] { probe.getClass().getName() }))); @@ -161,7 +166,8 @@ public class MongoExampleMapperUnitTests { IsBsonObject expected = isBsonObject().containing("flatDoc\\.stringValue", "conflux"); - assertThat(mapper.getMappedExample(of(probe), context.getPersistentEntity(WrapperDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(of(probe), context.getRequiredPersistentEntity(WrapperDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -173,7 +179,7 @@ public class MongoExampleMapperUnitTests { Example example = Example.of(probe, matching().withIncludeNullValues()); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(WrapperDocument.class)), // + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(WrapperDocument.class)), // isBsonObject().containing("flatDoc.stringValue", "conflux")); } @@ -190,7 +196,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue.$regex", "^firefight").// containing("intValue", 100); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -206,7 +212,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue.$regex", "^" + Pattern.quote("fire.ight")).// containing("intValue", 100); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -222,7 +228,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue.$regex", "firefight$").// containing("intValue", 100); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -238,7 +244,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue.$regex", "firefight").// containing("custom_field_name.$regex", "^(cat|dog).*shelter\\d?"); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -254,7 +260,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue", new org.bson.Document("$regex", "firefight$").append("$options", "i")).// containing("intValue", 100); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -270,7 +276,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue", new org.bson.Document("$regex", Pattern.quote("firefight")).append("$options", "i")).// containing("intValue", 100); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -281,10 +287,11 @@ public class MongoExampleMapperUnitTests { probe.referenceDocument = new ReferenceDocument(); probe.referenceDocument.id = "200"; - org.bson.Document document = mapper.getMappedExample(of(probe), context.getPersistentEntity(WithDBRef.class)); + org.bson.Document document = mapper.getMappedExample(of(probe), + context.getRequiredPersistentEntity(WithDBRef.class)); com.mongodb.DBRef reference = getTypedValue(document, "referenceDocument", com.mongodb.DBRef.class); - assertThat(reference.getId(), Is.is("200")); + assertThat(reference.getId(), Is. is("200")); assertThat(reference.getCollectionName(), is("refDoc")); } @@ -294,7 +301,8 @@ public class MongoExampleMapperUnitTests { FlatDocument probe = new FlatDocument(); probe.stringValue = "steelheart"; - org.bson.Document document = mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)); + org.bson.Document document = mapper.getMappedExample(of(probe), + context.getRequiredPersistentEntity(FlatDocument.class)); assertThat(document, isBsonObject().containing("stringValue", "steelheart")); } @@ -305,10 +313,11 @@ public class MongoExampleMapperUnitTests { ClassWithGeoTypes probe = new ClassWithGeoTypes(); probe.legacyPoint = new Point(10D, 20D); - org.bson.Document document = mapper.getMappedExample(of(probe), context.getPersistentEntity(WithDBRef.class)); + org.bson.Document document = mapper.getMappedExample(of(probe), + context.getRequiredPersistentEntity(WithDBRef.class)); - assertThat(document.get("legacyPoint.x"), Is.is(10D)); - assertThat(document.get("legacyPoint.y"), Is.is(20D)); + assertThat(document.get("legacyPoint.x"), Is. is(10D)); + assertThat(document.get("legacyPoint.y"), Is. is(20D)); } @Test // DATAMONGO-1245 @@ -325,7 +334,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue", "string").// containing("intValue", 10); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -342,7 +351,7 @@ public class MongoExampleMapperUnitTests { containing("custom_field_name", "foo").// containing("intValue", 10); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -360,7 +369,8 @@ public class MongoExampleMapperUnitTests { containing("flatDoc\\.custom_field_name", "foo").// containing("flatDoc\\.intValue", 10); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(WrapperDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(WrapperDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -378,7 +388,8 @@ public class MongoExampleMapperUnitTests { containing("flatDoc\\.stringValue", "string").// containing("flatDoc\\.intValue", 10); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(WrapperDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(WrapperDocument.class)), + is(expected)); } @Test // DATAMONGO-1245 @@ -394,7 +405,7 @@ public class MongoExampleMapperUnitTests { containing("stringValue.$regex", ".*firefight.*").// containing("custom_field_name", "steelheart"); - assertThat(mapper.getMappedExample(example, context.getPersistentEntity(FlatDocument.class)), is(expected)); + assertThat(mapper.getMappedExample(example, context.getRequiredPersistentEntity(FlatDocument.class)), is(expected)); } @Test // DATAMONGO-1245 @@ -405,7 +416,8 @@ public class MongoExampleMapperUnitTests { probe.customNamedField = "steelheart"; probe.anotherStringValue = "calamity"; - org.bson.Document document = mapper.getMappedExample(of(probe), context.getPersistentEntity(FlatDocument.class)); + org.bson.Document document = mapper.getMappedExample(of(probe), + context.getRequiredPersistentEntity(FlatDocument.class)); assertThat(document, isBsonObject().containing("anotherStringValue", "calamity")); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java index 953077b88..92c58c3c4 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java @@ -34,6 +34,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mapping.model.Property; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; @@ -87,7 +88,10 @@ public class BasicMongoPersistentPropertyUnitTests { @Test // DATAMONGO-553 public void usesPropertyAccessForThrowableCause() { - MongoPersistentProperty property = getPropertyFor(ReflectionUtils.findField(Throwable.class, "cause")); + BasicMongoPersistentEntity entity = new BasicMongoPersistentEntity<>( + ClassTypeInformation.from(Throwable.class)); + MongoPersistentProperty property = getPropertyFor(entity, "cause"); + assertThat(property.usePropertyAccess(), is(true)); } @@ -96,13 +100,13 @@ public class BasicMongoPersistentPropertyUnitTests { Field field = ReflectionUtils.findField(Person.class, "lastname"); - MongoPersistentProperty property = new BasicMongoPersistentProperty(field, null, entity, new SimpleTypeHolder(), - UppercaseFieldNamingStrategy.INSTANCE); + MongoPersistentProperty property = new BasicMongoPersistentProperty(Property.of(field), entity, + new SimpleTypeHolder(), UppercaseFieldNamingStrategy.INSTANCE); assertThat(property.getFieldName(), is("LASTNAME")); field = ReflectionUtils.findField(Person.class, "firstname"); - property = new BasicMongoPersistentProperty(field, null, entity, new SimpleTypeHolder(), + property = new BasicMongoPersistentProperty(Property.of(field), entity, new SimpleTypeHolder(), UppercaseFieldNamingStrategy.INSTANCE); assertThat(property.getFieldName(), is("foo")); } @@ -111,8 +115,8 @@ public class BasicMongoPersistentPropertyUnitTests { public void rejectsInvalidValueReturnedByFieldNamingStrategy() { Field field = ReflectionUtils.findField(Person.class, "lastname"); - MongoPersistentProperty property = new BasicMongoPersistentProperty(field, null, entity, new SimpleTypeHolder(), - InvalidFieldNamingStrategy.INSTANCE); + MongoPersistentProperty property = new BasicMongoPersistentProperty(Property.of(field), entity, + new SimpleTypeHolder(), InvalidFieldNamingStrategy.INSTANCE); exception.expect(MappingException.class); exception.expectMessage(InvalidFieldNamingStrategy.class.getName()); @@ -192,7 +196,7 @@ public class BasicMongoPersistentPropertyUnitTests { } private MongoPersistentProperty getPropertyFor(MongoPersistentEntity persistentEntity, Field field) { - return new BasicMongoPersistentProperty(field, null, persistentEntity, new SimpleTypeHolder(), + return new BasicMongoPersistentProperty(Property.of(field), persistentEntity, new SimpleTypeHolder(), PropertyNameFieldNamingStrategy.INSTANCE); }