diff --git a/pom.xml b/pom.xml index 50a3505945..6c52fce9ae 100644 --- a/pom.xml +++ b/pom.xml @@ -28,9 +28,10 @@ multi spring-data-mongodb - 2.0.0.BUILD-SNAPSHOT + 2.0.0.DATACMNS-867-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 4fd204dfc1..d21d05389a 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 @@ 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.ArrayList; @@ -29,11 +30,11 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Scanner; import java.util.Set; import java.util.concurrent.TimeUnit; -import com.mongodb.*; import org.bson.Document; import org.bson.conversions.Bson; import org.bson.types.ObjectId; @@ -104,6 +105,8 @@ 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; @@ -111,6 +114,15 @@ import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; +import com.mongodb.CommandResult; +import com.mongodb.Cursor; +import com.mongodb.DBCollection; +import com.mongodb.DBCursor; +import com.mongodb.Mongo; +import com.mongodb.MongoException; +import com.mongodb.ReadPreference; +import com.mongodb.WriteConcern; +import com.mongodb.WriteResult; import com.mongodb.client.FindIterable; import com.mongodb.client.MapReduceIterable; import com.mongodb.client.MongoCollection; @@ -353,7 +365,7 @@ public CloseableIterator stream(final Query query, final Class entityT 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); @@ -361,8 +373,7 @@ public CloseableIterator doInCollection(MongoCollection collection) FindIterable cursor = collection.find(mappedQuery).projection(mappedFields); QueryCursorPreparer cursorPreparer = new QueryCursorPreparer(query, entityType); - ReadDocumentCallback readCallback = new ReadDocumentCallback(mongoConverter, entityType, - collectionName); + ReadDocumentCallback readCallback = new ReadDocumentCallback(mongoConverter, entityType, collectionName); return new CloseableIterableCursorAdapter(cursorPreparer.prepare(cursor), exceptionTranslator, readCallback); } @@ -440,7 +451,7 @@ protected void executeQuery(Query query, String collectionName, DocumentCallback Assert.notNull(query); - Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), null); + Document queryObject = queryMapper.getMappedObject(query.getQueryObject(), Optional.empty()); Document sortObject = query.getSortObject(); Document fieldsObject = query.getFieldsObject(); @@ -632,9 +643,11 @@ public T findById(Object id, Class entityClass) { } 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); } @@ -752,13 +765,9 @@ public long count(Query query, Class entityClass, String collectionName) { Assert.hasText(collectionName); 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)); } /* @@ -877,13 +886,13 @@ private Document toDocument(T objectToSave, MongoWriter writer) { 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) { @@ -908,11 +917,7 @@ protected void doInsertAll(Collection listToSave, MongoWriter 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); @@ -969,41 +974,35 @@ public void save(Object objectToSave, String collectionName) { Assert.notNull(objectToSave); Assert.hasText(collectionName); - MongoPersistentEntity mongoPersistentEntity = getPersistentEntity(objectToSave.getClass()); - - // No optimistic locking -> simple save - if (mongoPersistentEntity == null || !mongoPersistentEntity.hasVersionProperty()) { - doSave(collectionName, objectToSave, this.mongoConverter); - return; - } + Optional> entity = getPersistentEntity(objectToSave.getClass()); + Optional versionProperty = entity.flatMap(it -> it.getVersionProperty()); - 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); + return mapIfAllPresent(versionProperty, versionNumber, (property, number) -> { - // Fresh instance -> initialize version property - if (version == null) { - doInsert(collectionName, objectToSave, this.mongoConverter); - } else { + MongoPersistentProperty idProperty = entity.getIdProperty()// + .orElseThrow(() -> new MappingException("Couldn't find identifier property on entity " + entity + "!")); assertUpdateableIdIfNotSet(objectToSave); // 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)); + Query query = Query.query(Criteria.where(idProperty.getName()).is(id).and(property.getName()).is(number)); // Bump version number - convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1); + convertingAccessor.setProperty(property, Optional.of(number.longValue() + 1)); Document document = new Document(); @@ -1021,10 +1020,16 @@ private void doSaveVersioned(T objectToSave, MongoPersistentEntity entity 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) { assertUpdateableIdIfNotSet(objectToSave); @@ -1037,6 +1042,8 @@ protected void doSave(String collectionName, T objectToSave, MongoWriter 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 +1181,8 @@ protected UpdateResult doUpdate(final String collectionName, final Query query, 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 +1218,23 @@ public UpdateResult doInCollection(MongoCollection collection) }); } - 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 +1264,21 @@ public DeleteResult remove(Object object, String collection) { * @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(); - - if (idProp == null || entity == null) { - throw new MappingException("No id property found for object of type " + objectType); - } + Optional> entity = mappingContext.getPersistentEntity(objectType); - Object idValue = entity.getPropertyAccessor(object).getProperty(idProp); - return Collections.singletonMap(idProp.getFieldName(), idValue).entrySet().iterator().next(); + return mapIfAllPresent(entity, entity.flatMap(it -> it.getIdProperty()), // + (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 +1289,8 @@ private Entry extractIdPropertyAndValue(Object object) { */ 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 +1304,38 @@ private Query getIdInQueryFor(Collection objects) { 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 +1359,7 @@ protected DeleteResult doRemove(final String collectionName, final Query que 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 +1439,7 @@ public MapReduceResults mapReduce(Query query, String inputCollectionName 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 +1485,7 @@ public GroupByResults group(Criteria criteria, String inputCollectionName 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 @@ -1745,7 +1753,7 @@ public MongoCollection doInDB(MongoDatabase db) throws MongoException, */ 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); @@ -1795,7 +1803,7 @@ protected List doFind(String collectionName, Document query, Document fie 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); @@ -1846,7 +1854,7 @@ protected T doFindAndRemove(String collectionName, Document query, Document 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); @@ -1861,7 +1869,7 @@ protected T doFindAndModify(String collectionName, Document query, Document options = new FindAndModifyOptions(); } - MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + Optional> entity = mappingContext.getPersistentEntity(entityClass); increaseVersionForUpdateIfNecessary(entity, update); @@ -1897,21 +1905,15 @@ protected void populateIdIfNecessary(Object savedObject, Object id) { return; } - MongoPersistentProperty idProp = getIdPropertyFor(savedObject.getClass()); - - if (idProp == null) { - return; - } - - ConversionService conversionService = mongoConverter.getConversionService(); - MongoPersistentEntity entity = mappingContext.getPersistentEntity(savedObject.getClass()); - PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject); + getIdPropertyFor(savedObject.getClass()).ifPresent(idProp -> { - if (accessor.getProperty(idProp) != null) { - return; - } + ConversionService conversionService = mongoConverter.getConversionService(); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(savedObject.getClass()); + PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject); - 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) { @@ -1939,7 +1941,7 @@ private MongoCollection getAndPrepareCollection(MongoDatabase db, Stri * @return */ private T executeFindOneInternal(CollectionCallback collectionCallback, - DocumentCallback objectCallback, String collectionName) { + DocumentCallback objectCallback, String collectionName) { try { T result = objectCallback @@ -1969,7 +1971,7 @@ private T executeFindOneInternal(CollectionCallback collectionCall * @return */ private List executeFindMultiInternal(CollectionCallback> collectionCallback, - CursorPreparer preparer, DocumentCallback objectCallback, String collectionName) { + CursorPreparer preparer, DocumentCallback objectCallback, String collectionName) { try { @@ -2042,13 +2044,12 @@ public PersistenceExceptionTranslator getExceptionTranslator() { 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) { @@ -2066,12 +2067,7 @@ String determineCollectionName(Class entityClass) { "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(); } /** @@ -2176,8 +2172,7 @@ static RuntimeException potentiallyConvertRuntimeException(RuntimeException ex, * * @param ids * @param documents - * @return - * TODO: Remove for 2.0 and change method signature of {@link #insertDBObjectList(String, List)}. + * @return TODO: Remove for 2.0 and change method signature of {@link #insertDBObjectList(String, List)}. */ private static List consolidateIdentifiers(List ids, List documents) { 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 14054d84cd..fd95e421e3 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.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.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; /** @@ -70,9 +70,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. @@ -90,12 +90,12 @@ public CustomConversions(List converters) { Assert.notNull(converters); - 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(); @@ -240,13 +240,8 @@ private void register(ConverterRegistration converterRegistration) { */ 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); } /** @@ -264,14 +259,8 @@ public Class getCustomWriteTarget(final Class sourceType, final Class r 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); } /** @@ -323,14 +312,8 @@ private Class getCustomReadTarget(final Class sourceType, final Class r 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); } /** @@ -342,54 +325,26 @@ public Class get() { * @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); Assert.notNull(pairs); 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 6f2838ef45..6e19ef6706 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 @@ 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 1f86a35115..837232cf33 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 @@ public Object populateId(MongoPersistentProperty property, DBRef source, Object 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 032aaa4d78..175d3cc411 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.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 DefaultDbRefResolver(MongoDbFactory mongoDbFactory) { * @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 2b395c083b..3b0f13f826 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 @@ 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.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 void writeTypeRestrictions(Document result, Set> restrictedTypes 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 DocumentTypeAliasAccessor(String typeKey) { * (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 ac978b15b6..58d3adc4dc 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 @@ 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 @@ public void put(MongoPersistentProperty prop, Object value) { } } + 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 d3585d0569..4ee92e2412 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.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.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 @@ private S read(TypeInformation type, Bson bson, ObjectPath } 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 @@ private S read(TypeInformation type, Bson bson, ObjectPath 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 @@ private ParameterValueProvider getParameterProvider(Mon 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 @@ private S read(final MongoPersistentEntity entity, final B final PersistentPropertyAccessor accessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(instance), conversionService); - final MongoPersistentProperty idProperty = entity.getIdProperty(); + final Optional idProperty = entity.getIdProperty(); final S result = instance; + DocumentAccessor documentAccessor = new DocumentAccessor(bson); // make sure id property is set before all other properties - Object idValue = null; - DocumentAccessor documentAccessor = new DocumentAccessor(bson); + Object idValue = idProperty.filter(it -> documentAccessor.hasValue(it)).map(it -> { - if (idProperty != null && documentAccessor.hasValue(idProperty)) { - idValue = getValueInternal(idProperty, bson, evaluator, path); - accessor.setProperty(idProperty, idValue); - } + Optional value = getValueInternal(it, bson, evaluator, path); + accessor.setProperty(it, value); - final ObjectPath currentPath = path.push(result, entity, idValue != null ? documentAccessor.get(idProperty) : null); + 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 void write(final Object obj, final Bson bson) { 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 void write(final Object obj, final Bson bson) { * @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 @@ protected void writeInternal(final Object obj, final Bson bson, final TypeInform } 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 @@ protected void writeInternal(Object obj, final Bson bson, MongoPersistentEntity< } 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); - - if (null != propertyObj) { + accessor.getProperty(prop).ifPresent(it -> { + if (!conversions.isSimpleType(it.getClass())) { - 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 void doWithPersistentProperty(MongoPersistentProperty prop) { 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 @@ protected void writePropertyInternal(Object obj, Bson bson, MongoPersistentPrope 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 @@ protected void writePropertyInternal(Object obj, Bson bson, MongoPersistentPrope 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 @@ private static Collection asCollection(Object source) { 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 @@ protected Bson createMap(Map map, MongoPersistentProperty proper * @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 @@ protected Bson writeMapInternal(Map obj, Bson bson, TypeInformat 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 @@ protected String potentiallyUnescapeMapKey(String source) { * @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 @@ protected DBRef createDBRef(Object target, MongoPersistentProperty property) { 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 @@ protected DBRef createDBRef(Object target, MongoPersistentProperty property) { * @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 @@ private Object readCollectionOrArray(TypeInformation targetType, List sourceV 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 @@ protected Map readMap(TypeInformation type, Bson bson, Object 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 @@ protected Map readMap(TypeInformation type, Bson bson, Object } 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 @@ private void addToMap(Bson bson, String key, Object value) { ((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 @@ private void addAllToMap(Bson bson, Map value) { 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 Object convertToMongoType(Object obj, TypeInformation typeInformation) 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 Object convertToMongoType(Object obj, TypeInformation typeInformation) } if (obj instanceof DBObject) { + Document newValueDbo = new Document(); for (String vk : ((DBObject) obj).keySet()) { @@ -1130,7 +1115,9 @@ public Object convertToMongoType(Object obj, TypeInformation typeInformation) 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 Object convertToMongoType(Object obj, TypeInformation typeInformation) 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 @@ private class MongoDbPropertyValueProvider implements PropertyValueProvider T getPropertyValue(MongoPersistentProperty property) { - - String expression = property.getSpelExpression(); - Object value = expression != null ? evaluator.evaluate(expression) : source.get(property); - - if (value == null) { - return null; - } + public Optional getPropertyValue(MongoPersistentProperty property) { + return Optional - 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 e43a9ff047..f7b80ff0b7 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.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 Document getMappedExample(Example example) { 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 Document getMappedExample(Example example) { * @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 Document getMappedExample(Example example, MongoPersistentEntity en 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 @@ private Set> getTypesToMatch(Example example) { 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 @@ private String getMappedPropertyPath(String path, Class probeType) { 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 ea16670205..8c583862a0 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 @@ 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 @@ public Object getPathItem(Object id, String collection) { * * @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 ce31d88dcc..3c481657a2 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.Iterator; import java.util.List; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import org.bson.Document; @@ -93,6 +94,10 @@ public QueryMapper(MongoConverter converter) { 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. @@ -166,6 +171,10 @@ public Document getMappedSort(Document sortObject, MongoPersistentEntity enti 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. @@ -182,6 +191,10 @@ public Document getMappedFields(Document fieldsObject, MongoPersistentEntity 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) { @@ -310,7 +323,7 @@ protected Object getMappedValue(Field documentField, Object value) { } else if (valueDbo.containsField("$ne")) { resultDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { - return getMappedObject(resultDbo, null); + return getMappedObject(resultDbo, Optional.empty()); } return resultDbo; } @@ -329,7 +342,7 @@ else if (isDocument(value)) { } else if (valueDbo.containsKey("$ne")) { resultDbo.put("$ne", convertId(valueDbo.get("$ne"))); } else { - return getMappedObject(resultDbo, null); + return getMappedObject(resultDbo, Optional.empty()); } return resultDbo; @@ -379,8 +392,8 @@ protected boolean isAssociationConversionNecessary(Field documentField, Object v } 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)); } /** @@ -519,28 +532,31 @@ private DBRef createDbRefFor(Object source, MongoPersistentProperty property) { 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); + } + }); } /** @@ -815,13 +831,9 @@ public MetadataBackedField with(String name) { @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)); } /* @@ -840,7 +852,7 @@ public MongoPersistentProperty getProperty() { @Override public MongoPersistentEntity getPropertyEntity() { MongoPersistentProperty property = getProperty(); - return property == null ? null : mappingContext.getPersistentEntity(property); + return property == null ? null : mappingContext.getRequiredPersistentEntity(property); } /* @@ -870,8 +882,11 @@ private final Association findAssociation() { 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 24a92a7eb7..006c18992e 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 a1196fca46..9545cf6fef 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.util.Comparator; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -52,8 +53,8 @@ * @author Thomas Darimont * @author Christoph Strobl */ -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(); @@ -72,24 +73,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(""); } /* @@ -126,7 +121,7 @@ public String getLanguage() { */ @Override public MongoPersistentProperty getTextScoreProperty() { - return getPersistentProperty(TextScore.class); + return getPersistentProperty(TextScore.class).orElse(null); } /* @@ -206,40 +201,38 @@ protected MongoPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNul return null; } - MongoPersistentProperty currentIdProperty = getIdProperty(); + Optional 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; } /** @@ -273,8 +266,8 @@ private static Expression detectExpression(Document document) { * * @author Oliver Gierke */ - private static class AssertFieldNameUniquenessHandler implements PropertyHandler, - AssociationHandler { + private static class AssertFieldNameUniquenessHandler + implements PropertyHandler, AssociationHandler { private final Map properties = new HashMap(); @@ -292,8 +285,8 @@ private void assertUniqueness(MongoPersistentProperty property) { MongoPersistentProperty existingProperty = properties.get(fieldName); if (existingProperty != null) { - throw new MappingException(String.format(AMBIGUOUS_FIELD_MAPPING, property.toString(), - existingProperty.toString(), fieldName)); + throw new MappingException( + String.format(AMBIGUOUS_FIELD_MAPPING, property.toString(), existingProperty.toString(), fieldName)); } properties.put(fieldName, property); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java index ab38336fb6..cc8849558e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java @@ -15,10 +15,9 @@ */ package org.springframework.data.mongodb.core.mapping; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Field; import java.math.BigInteger; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import org.bson.types.ObjectId; @@ -29,6 +28,7 @@ import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; 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.util.StringUtils; @@ -72,10 +72,10 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope * @param simpleTypeHolder * @param fieldNamingStrategy */ - public BasicMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, - MongoPersistentEntity 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 String getFieldName() { 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 @@ protected boolean hasExplicitFieldName() { 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 @@ private String getAnnotatedFieldName() { * @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 boolean isDbReference() { * @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 e9389162bf..e914353470 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 0000000000..21c05a9dd5 --- /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 c878062856..e9c21bac00 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.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 @@ protected boolean shouldCreatePersistentEntityFor(TypeInformation type) { * @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder) */ @Override - public MongoPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, - BasicMongoPersistentEntity 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 2a36ee2237..6ff05c4fd7 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 @@ 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.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; +import com.mongodb.BasicDBObject; + /** * Unit tests for {@link DocumentAccessor}. * @@ -37,8 +38,8 @@ 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 public void putsNestedFieldCorrectly() { @@ -84,14 +85,14 @@ public void rejectsNullDocument() { @Test 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"); @@ -107,11 +108,11 @@ public void writesAllNestingsCorrectly() { 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 adff1b3336..290448fa8d 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 void setUp() { mappingContext.setApplicationContext(context); mappingContext.afterPropertiesSet(); + mappingContext.getPersistentEntity(Address.class); + converter = new MappingMongoConverter(resolver, mappingContext); converter.afterPropertiesSet(); } @@ -458,7 +460,6 @@ public void readsClassWithBigDecimal() { } @Test - @SuppressWarnings("unchecked") public void writesNestedCollectionsCorrectly() { CollectionWrapper wrapper = new CollectionWrapper(); @@ -552,7 +553,6 @@ public void readsGenericTypeCorrectly() { GenericType result = converter.read(GenericType.class, new org.bson.Document("content", address)); assertThat(result.content, is(instanceOf(Address.class))); - } /** @@ -1318,7 +1318,6 @@ public void recursivelyConvertsSpELReadValue() { * @see DATAMONGO-724 */ @Test - @SuppressWarnings("unchecked") public void mappingConsidersCustomConvertersNotWritingTypeInformation() { Person person = new Person(); @@ -1565,8 +1564,8 @@ public void shouldWriteEntityWithGeoBoxCorrectly() { 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) { @@ -1612,7 +1611,7 @@ public void shouldWriteEntityWithGeoPolygonCorrectly() { 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)))); } @@ -1998,7 +1997,7 @@ public void readsOptionalsCorrectly() { 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))); } @@ -2006,7 +2005,6 @@ public void readsOptionalsCorrectly() { * @see DATAMONGO-1118 */ @Test - @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 c1f33ca41b..c1f8603f26 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 @@ -83,7 +83,8 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenIdIsSet() { 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)); } /** @@ -102,7 +103,8 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenMultipleValuesSet() { 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)); } /** @@ -119,7 +121,8 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenIdIsNotSet() { 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)); } /** @@ -136,7 +139,8 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenListHasValues() { 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)); } /** @@ -150,7 +154,8 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenFieldNameIsCustomized() 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)); } /** @@ -164,7 +169,7 @@ public void typedExampleShouldContainTypeRestriction() { 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() }))); @@ -182,7 +187,8 @@ public void exampleShouldBeMappedAsFlatMapWhenGivenNestedElementsWithLenientMatc 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)); } /** @@ -197,7 +203,7 @@ public void exampleShouldBeMappedAsExactObjectWhenGivenNestedElementsWithStrictM 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")); } @@ -217,7 +223,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenStringMatchModeIsStarti 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)); } /** @@ -236,7 +242,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeContainingDotsWhenStringMat 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)); } /** @@ -255,7 +261,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenStringMatchModeIsEnding 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)); } /** @@ -274,7 +280,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenStringMatchModeRegex() 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)); } /** @@ -293,7 +299,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenIgnoreCaseEnabledAndMat 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)); } /** @@ -312,7 +318,7 @@ public void exampleShouldBeMappedCorrectlyForFlatTypeWhenIgnoreCaseEnabled() { 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)); } /** @@ -326,10 +332,11 @@ public void exampleShouldBeMappedWhenContainingDBRef() { 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")); } @@ -342,7 +349,8 @@ public void exampleShouldBeMappedWhenDBRefIsNull() { 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")); } @@ -356,10 +364,11 @@ public void exampleShouldBeMappedCorrectlyWhenContainingLegacyPoint() { 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)); } /** @@ -379,7 +388,7 @@ public void mappingShouldExcludeFieldWithCustomNameCorrectly() { 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)); } /** @@ -399,7 +408,7 @@ public void mappingShouldExcludeFieldCorrectly() { 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)); } /** @@ -420,7 +429,8 @@ public void mappingShouldExcludeNestedFieldCorrectly() { 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)); } /** @@ -441,7 +451,8 @@ public void mappingShouldExcludeNestedFieldWithCustomNameCorrectly() { 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)); } /** @@ -460,7 +471,7 @@ public void mappingShouldFavorFieldSpecificationStringMatcherOverDefaultStringMa 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)); } /** @@ -474,7 +485,8 @@ public void mappingShouldIncludePropertiesFromHierarchicalDocument() { 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 5f325e7aab..cca0353de4 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.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; @@ -90,7 +91,10 @@ public void preventsNegativeOrder() { @Test 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)); } @@ -102,13 +106,13 @@ public void usesCustomFieldNamingStrategyByDefault() throws Exception { 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")); } @@ -120,8 +124,8 @@ public void usesCustomFieldNamingStrategyByDefault() throws Exception { 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()); @@ -225,7 +229,7 @@ private MongoPersistentProperty getPropertyFor(MongoPersistentEntity persiste } 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); }