diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java index f470dd8a1..6c1992fc5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -23,9 +23,13 @@ import org.bson.codecs.configuration.CodecRegistry; import org.springframework.util.Assert; /** + * Provider interface to obtain {@link CodecRegistry} from the underlying MongoDB Java driver. + * * @author Christoph Strobl + * @author Mark Paluch * @since 2.1 */ +@FunctionalInterface public interface CodecRegistryProvider { /** @@ -50,7 +54,7 @@ public interface CodecRegistryProvider { /** * Get the {@link Codec} registered for the given {@literal type} or an {@link Optional#empty() empty Optional} * instead. - * + * * @param type must not be {@literal null}. * @param * @return never {@literal null}. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java index 3604fe6ac..b46e624ce 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2018 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. @@ -25,15 +25,16 @@ import com.mongodb.client.MongoDatabase; /** * Interface for factories creating {@link DB} instances. - * + * * @author Mark Pollack * @author Thomas Darimont + * @author Christoph Strobl */ public interface MongoDbFactory extends CodecRegistryProvider { /** * Creates a default {@link DB} instance. - * + * * @return * @throws DataAccessException */ @@ -41,7 +42,7 @@ public interface MongoDbFactory extends CodecRegistryProvider { /** * Creates a {@link DB} instance to access the database with the given name. - * + * * @param dbName must not be {@literal null} or empty. * @return * @throws DataAccessException @@ -50,13 +51,18 @@ public interface MongoDbFactory extends CodecRegistryProvider { /** * Exposes a shared {@link MongoExceptionTranslator}. - * + * * @return will never be {@literal null}. */ PersistenceExceptionTranslator getExceptionTranslator(); DB getLegacyDb(); + /** + * Get the underlying {@link CodecRegistry} used by the MongoDB Java driver. + * + * @return never {@literal null}. + */ @Override default CodecRegistry getCodecRegistry() { return getDb().getCodecRegistry(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java index 46a945056..4ce6a714b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -56,6 +56,11 @@ public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider { */ PersistenceExceptionTranslator getExceptionTranslator(); + /** + * Get the underlying {@link CodecRegistry} used by the reactive MongoDB Java driver. + * + * @return never {@literal null}. + */ @Override default CodecRegistry getCodecRegistry() { return getMongoDatabase().getCodecRegistry(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java index 92bdb5e6e..d7becb8cb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -258,7 +258,7 @@ public interface ExecutableFindOperation { * to obtain the domain type.
* Using {@link Object} also works for non strictly typed fields. Eg. a mixture different types like fields using * {@link String} in one {@link org.bson.Document} while {@link Long} in another. - *
Any Simple type like {@link String}, {@link Long}, ...
+ *
Any Simple type like {@link String} or {@link Long}.
*
The result is mapped directly by the MongoDB Java driver and the {@link org.bson.codecs.CodeCodec Codecs} in * place. This works only for results where all documents considered for the operation use the very same type for * the field.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java index 8f15265d3..1987a9cce 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -209,12 +209,13 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { * (non-Javadoc) * @see org.springframework.data.mongodb.core.ExecutableFindOperation.FindDistinct#distinct(java.lang.String) */ + @SuppressWarnings("unchecked") @Override public TerminatingDistinct distinct(String field) { Assert.notNull(field, "Field must not be null!"); - return new DistinctOperationSupport<>(this, field); + return new DistinctOperationSupport(this, field); } private List doFind(@Nullable CursorPreparer preparer) { @@ -287,9 +288,9 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { static class DistinctOperationSupport implements TerminatingDistinct { private final String field; - private final ExecutableFindSupport delegate; + private final ExecutableFindSupport delegate; - public DistinctOperationSupport(ExecutableFindSupport delegate, String field) { + public DistinctOperationSupport(ExecutableFindSupport delegate, String field) { this.delegate = delegate; this.field = field; @@ -300,11 +301,12 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { * @see org.springframework.data.mongodb.core.ExecutableFindOperation.DistinctWithProjection#as(java.lang.Class) */ @Override + @SuppressWarnings("unchecked") public TerminatingDistinct as(Class resultType) { Assert.notNull(resultType, "ResultType must not be null!"); - return new DistinctOperationSupport((ExecutableFindSupport) delegate.as(resultType), field); + return new DistinctOperationSupport<>((ExecutableFindSupport) delegate.as(resultType), field); } /* @@ -316,7 +318,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { Assert.notNull(query, "Query must not be null!"); - return new DistinctOperationSupport((ExecutableFindSupport) delegate.matching(query), field); + return new DistinctOperationSupport<>((ExecutableFindSupport) delegate.matching(query), field); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java index d3f457dff..3d5268f8d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java @@ -761,7 +761,6 @@ public interface MongoOperations extends FluentMongoOperations { * @param field the name of the field to inspect for distinct values. Must not be {@literal null}. * @param collection the explicit name of the actual {@link MongoCollection}. Must not be {@literal null}. * @param resultClass the result type. Must not be {@literal null}. - * @param * @return never {@literal null}. * @since 2.1 */ 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 91bbf1533..338389d43 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 @@ -1,5 +1,5 @@ /* - * Copyright 2010-2017 the original author or authors. + * Copyright 2010-2018 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. @@ -121,7 +121,6 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; -import com.mongodb.Function; import com.mongodb.MongoClient; import com.mongodb.MongoException; import com.mongodb.ReadPreference; @@ -803,7 +802,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, } /* - * (non-Javadoc) + * (non-Javadoc) * @see org.springframework.data.mongodb.core.MongoOperations#findDistinct(org.springframework.data.mongodb.core.query.Query, java.lang.String, java.lang.Class, java.lang.Class) */ @Override @@ -816,6 +815,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, * @see org.springframework.data.mongodb.core.MongoOperations#findDistinct(org.springframework.data.mongodb.core.query.Query, java.lang.String, java.lang.String, java.lang.Class, java.lang.Class) */ @Override + @SuppressWarnings("unchecked") public List findDistinct(Query query, String field, String collectionName, Class entityClass, Class resultClass) { @@ -830,20 +830,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), entity); String mappedFieldName = queryMapper.getMappedFields(new Document(field, 1), entity).keySet().iterator().next(); - Class mongoDriverCompatibleType = getMongoDbFactory().getCodecFor(resultClass).map(Codec::getEncoderClass) + Class mongoDriverCompatibleType = getMongoDbFactory().getCodecFor(resultClass).map(Codec::getEncoderClass) .orElse((Class) BsonValue.class); MongoIterable result = execute((db) -> { - DistinctIterable iterable = db.getCollection(collectionName).distinct(mappedFieldName, mappedQuery, + DistinctIterable iterable = db.getCollection(collectionName).distinct(mappedFieldName, mappedQuery, mongoDriverCompatibleType); - return query.getCollation().isPresent() - ? iterable.collation(query.getCollation().map(Collation::toMongoCollation).get()) : iterable; + return query.getCollation().map(Collation::toMongoCollation).map(iterable::collation).orElse(iterable); }); if (resultClass == Object.class || mongoDriverCompatibleType != resultClass) { - result = result.map(mapDistinctResult(getMostSpecificConversionTargetType(resultClass, entityClass, field))); + + MongoConverter converter = getConverter(); + DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory); + + result = result.map((source) -> converter.mapValueToTargetType(source, + getMostSpecificConversionTargetType(resultClass, entityClass, field), dbRefResolver)); } try { @@ -860,7 +864,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, * @return the most specific conversion target type depending on user preference and domain type property. * @since 2.1 */ - private Class getMostSpecificConversionTargetType(Class userType, Class domainType, String field) { + private static Class getMostSpecificConversionTargetType(Class userType, Class domainType, String field) { Class conversionTargetType = userType; try { @@ -879,16 +883,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return conversionTargetType; } - /** - * @param targetType the desired conversion target type. - * @return new {@link Function} converting {@link BsonValue} into desired target type. - * @since 2.1 - */ - private Function mapDistinctResult(Class targetType) { - return (source) -> getConverter().mapValueToTargetType(targetType, new DefaultDbRefResolver(mongoDbFactory)) - .apply(source); - } - @Override public GeoResults geoNear(NearQuery near, Class entityClass) { return geoNear(near, entityClass, determineCollectionName(entityClass)); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java index 4e28f850f..8dbc357d3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java index d72f30505..90aa9f2de 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -217,6 +217,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation { preparer != null ? preparer : getCursorPreparer(query)); } + @SuppressWarnings("unchecked") private Flux doFindDistinct(String field) { return template.findDistinct(query, field, getCollectionName(), domainType, @@ -259,7 +260,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation { Assert.notNull(resultType, "ResultType must not be null!"); - return new DistinctOperationSupport((ReactiveFindSupport) delegate.as(resultType), field); + return new DistinctOperationSupport<>((ReactiveFindSupport) delegate.as(resultType), field); } /* @@ -267,11 +268,12 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation { * @see org.springframework.data.mongodb.core.ReactiveFindOperation.DistinctWithQuery#matching(org.springframework.data.mongodb.core.query.Query) */ @Override + @SuppressWarnings("unchecked") public TerminatingDistinct matching(Query query) { Assert.notNull(query, "Query must not be null!"); - return new DistinctOperationSupport((ReactiveFindSupport) delegate.matching(query), field); + return new DistinctOperationSupport<>((ReactiveFindSupport) delegate.matching(query), field); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java index 20161a02c..d9ca552a3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java @@ -379,7 +379,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Finds the distinct values for a specified {@literal field} across a single {@link MongoCollection} or view and - * returns the results in a {@link List}. + * returns the results in a {@link Flux}. * * @param field the name of the field to inspect for distinct values. Must not be {@literal null}. * @param entityClass the domain type used for determining the actual {@link MongoCollection}. Must not be @@ -394,7 +394,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Finds the distinct values for a specified {@literal field} across a single {@link MongoCollection} or view and - * returns the results in a {@link List}. + * returns the results in a {@link Flux}. * * @param query filter {@link Query} to restrict search. Must not be {@literal null}. * @param field the name of the field to inspect for distinct values. Must not be {@literal null}. @@ -408,7 +408,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Finds the distinct values for a specified {@literal field} across a single {@link MongoCollection} or view and - * returns the results in a {@link List}. + * returns the results in a {@link Flux}. * * @param query filter {@link Query} to restrict search. Must not be {@literal null}. * @param field the name of the field to inspect for distinct values. Must not be {@literal null}. @@ -423,14 +423,13 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Finds the distinct values for a specified {@literal field} across a single {@link MongoCollection} or view and - * returns the results in a {@link List}. + * returns the results in a {@link Flux}. * * @param query filter {@link Query} to restrict search. Must not be {@literal null}. * @param field the name of the field to inspect for distinct values. Must not be {@literal null}. * @param collection the explicit name of the actual {@link MongoCollection}. Must not be {@literal null}. * @param resultClass the result type. Must not be {@literal null}. - * @param - * @return + * @return never {@literal null}. * @since 2.1 */ default Flux findDistinct(Query query, String field, String collection, Class resultClass) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java index ba8af473c..46e6ea434 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2016-2018 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. @@ -24,17 +24,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -692,6 +683,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#findDistinct(org.springframework.data.mongodb.core.query.Query, java.lang.String, java.lang.String, java.lang.Class, java.lang.Class) */ + @SuppressWarnings("unchecked") public Flux findDistinct(Query query, String field, String collectionName, Class entityClass, Class resultClass) { @@ -706,23 +698,25 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), entity); String mappedFieldName = queryMapper.getMappedFields(new Document(field, 1), entity).keySet().iterator().next(); - Class mongoDriverCompatibleType = mongoDatabaseFactory.getCodecFor(resultClass).map(Codec::getEncoderClass) + Class mongoDriverCompatibleType = mongoDatabaseFactory.getCodecFor(resultClass).map(Codec::getEncoderClass) .orElse((Class) BsonValue.class); - Flux result = execute(collectionName, collection -> { + Flux result = execute(collectionName, collection -> { - DistinctPublisher publisher = collection.distinct(mappedFieldName, mappedQuery, mongoDriverCompatibleType); + DistinctPublisher publisher = collection.distinct(mappedFieldName, mappedQuery, mongoDriverCompatibleType); - return query.getCollation().isPresent() - ? publisher.collation(query.getCollation().map(Collation::toMongoCollation).get()) : publisher; + return query.getCollation().map(Collation::toMongoCollation).map(publisher::collation).orElse(publisher); }); if (resultClass == Object.class || mongoDriverCompatibleType != resultClass) { - result = result.map( - getConverter().mapValueToTargetType(getMostSpecificConversionTargetType(resultClass, entityClass, field), NO_OP_REF_RESOLVER)); + + Class targetType = getMostSpecificConversionTargetType(resultClass, entityClass, field); + MongoConverter converter = getConverter(); + + result = result.map(it -> converter.mapValueToTargetType(it, targetType, NO_OP_REF_RESOLVER)); } - return result; + return (Flux) result; } /** @@ -732,7 +726,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati * @return the most specific conversion target type depending on user preference and domain type property. * @since 2.1 */ - private Class getMostSpecificConversionTargetType(Class userType, Class domainType, String field) { + private static Class getMostSpecificConversionTargetType(Class userType, Class domainType, String field) { Class conversionTargetType = userType; try { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java index 442f4cc6a..41d5aa62e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 the original author or authors. + * Copyright 2010-2018 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. @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.core.convert; -import java.util.function.Function; - import org.bson.BsonValue; import org.bson.Document; import org.bson.conversions.Bson; @@ -26,17 +24,19 @@ import org.springframework.data.convert.TypeMapper; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.util.BsonUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import com.mongodb.DBRef; /** - * Central Mongo specific converter interface which combines {@link MongoWriter} and {@link MongoReader}. - * + * Central Mongo specific converter interface which combines {@link MongoWriter} and {@link EntityReader}. + * * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public interface MongoConverter extends EntityConverter, MongoPersistentProperty, Object, Bson>, MongoWriter, @@ -45,7 +45,7 @@ public interface MongoConverter /** * Returns thw {@link TypeMapper} being used to write type information into {@link Document}s created with that * converter. - * + * * @return will never be {@literal null}. */ MongoTypeMapper getTypeMapper(); @@ -58,50 +58,49 @@ public interface MongoConverter * @param dbRefResolver must not be {@literal null}. * @param * @param - * @return new typed {@link com.mongodb.Function}. + * @return new typed {@link java.util.function.Function}. * @throws IllegalArgumentException if {@literal targetType} is {@literal null}. * @since 2.1 */ - default Function mapValueToTargetType(Class targetType, DbRefResolver dbRefResolver) { + @SuppressWarnings("unchecked") + @Nullable + default T mapValueToTargetType(S source, Class targetType, DbRefResolver dbRefResolver) { Assert.notNull(targetType, "TargetType must not be null!"); Assert.notNull(dbRefResolver, "DbRefResolver must not be null!"); - return (source) -> { - if (targetType != Object.class && ClassUtils.isAssignable(targetType, source.getClass())) { - return (T) source; - } + if (targetType != Object.class && ClassUtils.isAssignable(targetType, source.getClass())) { + return (T) source; + } - if (source instanceof BsonValue) { + if (source instanceof BsonValue) { - Object value = BsonUtils.toJavaType((BsonValue) source); + Object value = BsonUtils.toJavaType((BsonValue) source); - if (value instanceof Document) { + if (value instanceof Document) { - Document sourceDocument = (Document) value; + Document sourceDocument = (Document) value; - if (sourceDocument.containsKey("$ref") && sourceDocument.containsKey("$id")) { + if (sourceDocument.containsKey("$ref") && sourceDocument.containsKey("$id")) { - sourceDocument = dbRefResolver - .fetch(new DBRef(sourceDocument.getString("$ref"), sourceDocument.get("$id"))); - if (sourceDocument == null) { - return null; - } - } - - return read(targetType, sourceDocument); - } else { - if (!ClassUtils.isAssignable(targetType, value.getClass())) { - if (getConversionService().canConvert(value.getClass(), targetType)) { - return getConversionService().convert(value, targetType); - } + sourceDocument = dbRefResolver.fetch(new DBRef(sourceDocument.getString("$ref"), sourceDocument.get("$id"))); + if (sourceDocument == null) { + return null; } } - return (T) value; + return read(targetType, sourceDocument); + } else { + if (!ClassUtils.isAssignable(targetType, value.getClass())) { + if (getConversionService().canConvert(value.getClass(), targetType)) { + return getConversionService().convert(value, targetType); + } + } } - return (T) getConversionService().convert(source, targetType); - }; + + return (T) value; + } + return getConversionService().convert(source, targetType); } } diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt index e0bb3ec85..03b1ca734 100644 --- a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensions.kt @@ -338,7 +338,7 @@ inline fun MongoOperations.findDistinct(field: String, entityC * @since 2.1 */ inline fun MongoOperations.findDistinct(query: Query, field: String, entityClass: KClass<*>): List = - findDistinct(query, field, entityClass.java, T::class.java); + findDistinct(query, field, entityClass.java, T::class.java) /** * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. @@ -346,17 +346,19 @@ inline fun MongoOperations.findDistinct(query: Query, field: S * @author Christoph Strobl * @since 2.1 */ -inline fun MongoOperations.findDistinct(query: Query, field: String, collectionName: String?, entityClass: KClass<*>): List = - findDistinct(query, field, collectionName, entityClass.java, T::class.java); +inline fun MongoOperations.findDistinct(query: Query, field: String, collectionName: String, entityClass: KClass<*>): List = + findDistinct(query, field, collectionName, entityClass.java, T::class.java) /** * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. * * @author Christoph Strobl + * @author Mark Paluch * @since 2.1 */ -inline fun MongoOperations.findDistinct(query: Query, field: String, collectionName: String?): List = - findDistinct(query, field, collectionName, T::class.java); +inline fun MongoOperations.findDistinct(query: Query, field: String, collectionName: String? = null): List = + if (collectionName != null) findDistinct(query, field, collectionName, E::class.java, T::class.java) + else findDistinct(query, field, E::class.java, T::class.java) /** * Extension for [MongoOperations.findAndModify] leveraging reified type parameters. diff --git a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt index e06d0f40e..832f87349 100644 --- a/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt +++ b/spring-data-mongodb/src/main/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensions.kt @@ -109,7 +109,6 @@ fun ReactiveMongoOperations.dropCollection(entityClass: KClass): Mo inline fun ReactiveMongoOperations.dropCollection(): Mono = dropCollection(T::class.java) - /** * Extension for [ReactiveMongoOperations.findAll] leveraging reified type parameters. * @@ -166,7 +165,7 @@ inline fun ReactiveMongoOperations.findById(id: Any, collectio if (collectionName != null) findById(id, T::class.java, collectionName) else findById(id, T::class.java) /** - * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. + * Extension for [ReactiveMongoOperations.findDistinct] leveraging reified type parameters. * * @author Christoph Strobl * @since 2.1 @@ -175,31 +174,33 @@ inline fun ReactiveMongoOperations.findDistinct(field: String, findDistinct(field, entityClass.java, T::class.java); /** - * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. + * Extension for [ReactiveMongoOperations.findDistinct] leveraging reified type parameters. * * @author Christoph Strobl * @since 2.1 */ inline fun ReactiveMongoOperations.findDistinct(query: Query, field: String, entityClass: KClass<*>): Flux = - findDistinct(query, field, entityClass.java, T::class.java); + findDistinct(query, field, entityClass.java, T::class.java) /** - * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. + * Extension for [ReactiveMongoOperations.findDistinct] leveraging reified type parameters. * * @author Christoph Strobl * @since 2.1 */ -inline fun ReactiveMongoOperations.findDistinct(query: Query, field: String, collectionName: String?, entityClass: KClass<*>): Flux = - findDistinct(query, field, collectionName, entityClass.java, T::class.java); +inline fun ReactiveMongoOperations.findDistinct(query: Query, field: String, collectionName: String, entityClass: KClass<*>): Flux = + findDistinct(query, field, collectionName, entityClass.java, T::class.java) /** - * Extension for [MongoOperations.findDistinct] leveraging reified type parameters. + * Extension for [ReactiveMongoOperations.findDistinct] leveraging reified type parameters. * * @author Christoph Strobl + * @author Mark Paluch * @since 2.1 */ -inline fun ReactiveMongoOperations.findDistinct(query: Query, field: String, collectionName: String?): Flux = - findDistinct(query, field, collectionName, T::class.java); +inline fun ReactiveMongoOperations.findDistinct(query: Query, field: String, collectionName: String? = null): Flux = + if (collectionName != null) findDistinct(query, field, collectionName, E::class.java, T::class.java) + else findDistinct(query, field, E::class.java, T::class.java) /** * Extension for [ReactiveMongoOperations.geoNear] leveraging reified type parameters. diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java index fd7d3407c..93b5c7a0c 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -372,7 +372,7 @@ public class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 - public void distinctReturnsSimpleFieldValuesCorrectlyForCollectionHavingNoReturnTypeSpecified() { + public void distinctReturnsSimpleFieldValuesCorrectly() { Person anakin = new Person(); anakin.firstname = "anakin"; @@ -395,7 +395,7 @@ public class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingNoReturnTypeSpecified() { + public void distinctReturnsComplexValuesCorrectly() { Sith sith = new Sith(); sith.rank = "lord"; @@ -410,7 +410,7 @@ public class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingReturnTypeSpecified() { + public void distinctReturnsComplexValuesCorrectlyHavingReturnTypeSpecified() { Sith sith = new Sith(); sith.rank = "lord"; @@ -426,7 +426,7 @@ public class ExecutableFindOperationSupportTests { } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingReturnTypeDocumentSpecified() { + public void distinctReturnsComplexValuesCorrectlyHavingReturnTypeDocumentSpecified() { Sith sith = new Sith(); sith.rank = "lord"; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java index fdea09cda..a3218392b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -114,15 +114,17 @@ public class ReactiveFindOperationSupportTests { @Test // DATAMONGO-1719 public void findAllWithProjection() { - StepVerifier.create(template.query(Person.class).as(Jedi.class).all().map(it -> it.getClass().getName())) - .expectNext(Jedi.class.getName(), Jedi.class.getName()).verifyComplete(); + StepVerifier.create(template.query(Person.class).as(Jedi.class).all().map(it -> it.getClass().getName())) // + .expectNext(Jedi.class.getName(), Jedi.class.getName()) // + .verifyComplete(); } @Test // DATAMONGO-1719 public void findAllBy() { - StepVerifier.create(template.query(Person.class).matching(query(where("firstname").is("luke"))).all()) - .expectNext(luke).verifyComplete(); + StepVerifier.create(template.query(Person.class).matching(query(where("firstname").is("luke"))).all()) // + .expectNext(luke) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -130,7 +132,8 @@ public class ReactiveFindOperationSupportTests { StepVerifier .create(template.query(Jedi.class).inCollection(STAR_WARS).matching(query(where("name").is("luke"))).all()) - .consumeNextWith(it -> assertThat(it).isInstanceOf(Jedi.class)).verifyComplete(); + .consumeNextWith(it -> assertThat(it).isInstanceOf(Jedi.class)) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -139,7 +142,8 @@ public class ReactiveFindOperationSupportTests { StepVerifier .create( template.query(Human.class).inCollection(STAR_WARS).matching(query(where("firstname").is("luke"))).all()) - .expectNextCount(1).verifyComplete(); + .expectNextCount(1) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -147,7 +151,8 @@ public class ReactiveFindOperationSupportTests { StepVerifier .create(template.query(Person.class).as(Jedi.class).matching(query(where("firstname").is("luke"))).all()) - .consumeNextWith(it -> assertThat(it).isInstanceOf(Jedi.class)).verifyComplete(); + .consumeNextWith(it -> assertThat(it).isInstanceOf(Jedi.class)) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -159,7 +164,8 @@ public class ReactiveFindOperationSupportTests { assertThat(it).isInstanceOf(PersonProjection.class); assertThat(it.getFirstname()).isEqualTo("luke"); - }).verifyComplete(); + }) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -170,14 +176,16 @@ public class ReactiveFindOperationSupportTests { assertThat(it).isInstanceOf(PersonSpELProjection.class); assertThat(it.getName()).isEqualTo("luke"); - }).verifyComplete(); + }) // + .verifyComplete(); } @Test // DATAMONGO-1719 public void findBy() { StepVerifier.create(template.query(Person.class).matching(query(where("firstname").is("luke"))).one()) - .expectNext(luke).verifyComplete(); + .expectNext(luke) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -191,7 +199,8 @@ public class ReactiveFindOperationSupportTests { public void findByTooManyResults() { StepVerifier.create(template.query(Person.class).matching(query(where("firstname").in("han", "luke"))).one()) - .expectError(IncorrectResultSizeDataAccessException.class).verify(); + .expectError(IncorrectResultSizeDataAccessException.class) // + .verify(); } @Test // DATAMONGO-1719 @@ -209,7 +218,9 @@ public class ReactiveFindOperationSupportTests { StepVerifier.create(template.query(Planet.class).near(NearQuery.near(-73.9667, 40.78).spherical(true)).all()) .consumeNextWith(actual -> { assertThat(actual.getDistance()).isNotNull(); - }).expectNextCount(1).verifyComplete(); + }) // + .expectNextCount(1) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -229,7 +240,9 @@ public class ReactiveFindOperationSupportTests { assertThat(actual.getDistance()).isNotNull(); assertThat(actual.getContent()).isInstanceOf(Human.class); assertThat(actual.getContent().getId()).isEqualTo("alderan"); - }).expectNextCount(1).verifyComplete(); + }) // + .expectNextCount(1) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -250,7 +263,9 @@ public class ReactiveFindOperationSupportTests { assertThat(it.getDistance()).isNotNull(); assertThat(it.getContent()).isInstanceOf(PlanetProjection.class); assertThat(it.getContent().getName()).isEqualTo("alderan"); - }).expectNextCount(1).verifyComplete(); + }) // + .expectNextCount(1) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -271,7 +286,9 @@ public class ReactiveFindOperationSupportTests { assertThat(it.getDistance()).isNotNull(); assertThat(it.getContent()).isInstanceOf(PlanetSpELProjection.class); assertThat(it.getContent().getId()).isEqualTo("alderan"); - }).expectNextCount(1).verifyComplete(); + }) // + .expectNextCount(1) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -289,7 +306,8 @@ public class ReactiveFindOperationSupportTests { StepVerifier .create(template.query(Person.class).matching(query(where("firstname").is(luke.getFirstname()))).count()) - .expectNext(1L).verifyComplete(); + .expectNext(1L) // + .verifyComplete(); } @Test // DATAMONGO-1719 @@ -310,14 +328,16 @@ public class ReactiveFindOperationSupportTests { StepVerifier .create(template.query(Person.class).matching(query(where("firstname").is(luke.getFirstname()))).exists()) - .expectNext(true).verifyComplete(); + .expectNext(true) // + .verifyComplete(); } @Test // DATAMONGO-1719 public void existsShouldReturnFalseWhenNoElementMatchesQuery() { StepVerifier.create(template.query(Person.class).matching(query(where("firstname").is("spock"))).exists()) - .expectNext(false).verifyComplete(); + .expectNext(false) // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -337,11 +357,12 @@ public class ReactiveFindOperationSupportTests { blocking.save(anakin); StepVerifier.create(template.query(Person.class).distinct("lastname").as(String.class).all()) - .assertNext(in("solo", "skywalker")).assertNext(in("solo", "skywalker")).verifyComplete(); + .assertNext(in("solo", "skywalker")).assertNext(in("solo", "skywalker")) // + .verifyComplete(); } @Test // DATAMONGO-1761 - public void distinctReturnsSimpleFieldValuesCorrectlyForCollectionHavingNoReturnTypeSpecified() { + public void distinctReturnsSimpleFieldValuesCorrectly() { Person anakin = new Person(); anakin.firstname = "anakin"; @@ -361,12 +382,15 @@ public class ReactiveFindOperationSupportTests { Consumer containedInAbilities = in(anakin.ability, padme.ability, jaja.ability); - StepVerifier.create(template.query(Person.class).distinct("ability").all()).assertNext(containedInAbilities) - .assertNext(containedInAbilities).assertNext(containedInAbilities).verifyComplete(); + StepVerifier.create(template.query(Person.class).distinct("ability").all()) // + .assertNext(containedInAbilities) // + .assertNext(containedInAbilities) // + .assertNext(containedInAbilities) // + .verifyComplete(); } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingNoReturnTypeSpecified() { + public void distinctReturnsComplexValuesCorrectly() { Sith sith = new Sith(); sith.rank = "lord"; @@ -377,12 +401,13 @@ public class ReactiveFindOperationSupportTests { blocking.save(anakin); - StepVerifier.create(template.query(Person.class).distinct("ability").all()).expectNext(anakin.ability) + StepVerifier.create(template.query(Person.class).distinct("ability").all()) // + .expectNext(anakin.ability) // .verifyComplete(); } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingReturnTypeSpecified() { + public void distinctReturnsComplexValuesCorrectlyHavingReturnTypeSpecified() { Sith sith = new Sith(); sith.rank = "lord"; @@ -393,12 +418,13 @@ public class ReactiveFindOperationSupportTests { blocking.save(anakin); - StepVerifier.create(template.query(Person.class).distinct("ability").as(Sith.class).all()).expectNext(sith) + StepVerifier.create(template.query(Person.class).distinct("ability").as(Sith.class).all()) // + .expectNext(sith) // .verifyComplete(); } @Test // DATAMONGO-1761 - public void distinctReturnsComplexValuesCorrectlyForCollectionHavingReturnTypeDocumentSpecified() { + public void distinctReturnsComplexValuesCorrectlyReturnTypeDocumentSpecified() { Sith sith = new Sith(); sith.rank = "lord"; @@ -410,14 +436,16 @@ public class ReactiveFindOperationSupportTests { blocking.save(anakin); StepVerifier.create(template.query(Person.class).distinct("ability").as(Document.class).all()) - .expectNext(new Document("rank", "lord").append("_class", Sith.class.getName())).verifyComplete(); + .expectNext(new Document("rank", "lord").append("_class", Sith.class.getName())) // + .verifyComplete(); } @Test // DATAMONGO-1761 public void distinctMapsFieldNameCorrectly() { StepVerifier.create(template.query(Jedi.class).inCollection(STAR_WARS).distinct("name").as(String.class).all()) - .assertNext(in("han", "luke")).assertNext(in("han", "luke")).verifyComplete(); + .assertNext(in("han", "luke")).assertNext(in("han", "luke")) // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -425,7 +453,9 @@ public class ReactiveFindOperationSupportTests { Consumer inValues = in(new BsonString("solo"), new BsonString("skywalker")); StepVerifier.create(template.query(Person.class).distinct("lastname").as(BsonValue.class).all()) - .assertNext(inValues).assertNext(inValues).verifyComplete(); + .assertNext(inValues) // + .assertNext(inValues) // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -433,7 +463,9 @@ public class ReactiveFindOperationSupportTests { blocking.save(new Document("darth", "vader"), STAR_WARS); - StepVerifier.create(template.query(Person.class).distinct("darth").all()).expectNext("vader").verifyComplete(); + StepVerifier.create(template.query(Person.class).distinct("darth").all()) // + .expectNext("vader") // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -445,7 +477,8 @@ public class ReactiveFindOperationSupportTests { blocking.save(luke); StepVerifier.create(template.query(Person.class).distinct("father").as(Jedi.class).all()) - .expectNext(new Jedi("anakin")).verifyComplete(); + .expectNext(new Jedi("anakin")) // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -457,7 +490,8 @@ public class ReactiveFindOperationSupportTests { blocking.save(luke); StepVerifier.create(template.query(Object.class).inCollection(STAR_WARS).distinct("father").as(Jedi.class).all()) - .expectNext(new Jedi("anakin")).verifyComplete(); + .expectNext(new Jedi("anakin")) // + .verifyComplete(); } @Test // DATAMONGO-1761 @@ -471,13 +505,17 @@ public class ReactiveFindOperationSupportTests { Person expected = new Person(); expected.firstname = luke.father.firstname; - StepVerifier.create(template.query(Person.class).distinct("father").all()).expectNext(expected).verifyComplete(); + StepVerifier.create(template.query(Person.class).distinct("father").all()) // + .expectNext(expected) // + .verifyComplete(); } @Test // DATAMONGO-1761 public void distinctThrowsExceptionWhenExplicitMappingTypeCannotBeApplied() { + StepVerifier.create(template.query(Person.class).distinct("firstname").as(Long.class).all()) - .expectError(InvalidDataAccessApiUsageException.class).verify(); + .expectError(InvalidDataAccessApiUsageException.class) // + .verify(); } interface Contact {} diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt index 76008cac5..13125c6a4 100644 --- a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/MongoOperationsExtensionsTests.kt @@ -36,6 +36,7 @@ import org.springframework.data.mongodb.core.query.Update /** * @author Sebastien Deleuze * @author Mark Paluch + * @author Christoph Strobl */ @RunWith(MockitoJUnitRunner::class) class MongoOperationsExtensionsTests { @@ -704,12 +705,30 @@ class MongoOperationsExtensionsTests { verify(operations).findDistinct(query, "field", "collection", First::class.java, String::class.java) } + @Test // DATAMONGO-1761 + fun `findDistinctImplicit(Query, String) should call java counterpart`() { + + val query = mock() + + operations.findDistinct(query, "field") + verify(operations).findDistinct(query, "field", First::class.java, String::class.java) + } + @Test // DATAMONGO-1761 fun `findDistinct(Query, String, String) should call java counterpart`() { val query = mock() - operations.findDistinct(query, "field", "collection") - verify(operations).findDistinct(query, "field", "collection", String::class.java) + operations.findDistinct(query, "field", "collection") + verify(operations).findDistinct(query, "field", "collection", First::class.java, String::class.java) + } + + @Test // DATAMONGO-1761 + fun `findDistinct(Query, String, KClass) should call java counterpart`() { + + val query = mock() + + operations.findDistinct(query, "field", First::class) + verify(operations).findDistinct(query, "field", First::class.java, String::class.java) } } diff --git a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt index b2f0ecaaf..2a3bd7d7f 100644 --- a/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt +++ b/spring-data-mongodb/src/test/kotlin/org/springframework/data/mongodb/core/ReactiveMongoOperationsExtensionsTests.kt @@ -30,6 +30,8 @@ import reactor.core.publisher.Mono /** * @author Sebastien Deleuze + * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(MockitoJUnitRunner::class) class ReactiveMongoOperationsExtensionsTests { @@ -552,12 +554,31 @@ class ReactiveMongoOperationsExtensionsTests { verify(operations).findDistinct(query, "field", "collection", First::class.java, String::class.java) } + @Test // DATAMONGO-1761 + fun `findDistinctImplicit(Query, String) should call java counterpart`() { + + val query = mock() + + operations.findDistinct(query, "field") + verify(operations).findDistinct(query, "field", First::class.java, String::class.java) + } + @Test // DATAMONGO-1761 fun `findDistinct(Query, String, String) should call java counterpart`() { val query = mock() - operations.findDistinct(query, "field", "collection") - verify(operations).findDistinct(query, "field", "collection", String::class.java) + operations.findDistinct(query, "field", "collection") + verify(operations).findDistinct(query, "field", "collection", First::class.java, String::class.java) + } + + + @Test // DATAMONGO-1761 + fun `findDistinct(Query, String, KClass) should call java counterpart`() { + + val query = mock() + + operations.findDistinct(query, "field", First::class) + verify(operations).findDistinct(query, "field", First::class.java, String::class.java) } } diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 57e6addb3..00c8abd3c 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -4,6 +4,7 @@ [[new-features.2-1-0]] == What's new in Spring Data MongoDB 2.1 * Cursor-based aggregation execution. +* <> for imperative and reactive Template API. [[new-features.2-0-0]] == What's new in Spring Data MongoDB 2.0 diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index 70ea97a32..f3afc8336 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -1090,8 +1090,9 @@ The query methods need to specify the target type T that will be returned and th [[mongo-template.query.distinct]] === Query distinct values -MongoDB allows obtaining distinct field values for a single field. The stored values do not have to have the same data type to be considered, nor is the feature limited to simple types. -However when retrieving distinct values the actual result type does matter for the sake of conversion. +MongoDB provides an operation to obtain distinct values for a single field using a query from the resulting documents. +Resulting values are not required to have the same data type, nor is the feature limited to simple types. +For retriaval the actual result type does matter for the sake of conversion and typing. .Retrieving distinct values ==== @@ -1100,13 +1101,13 @@ However when retrieving distinct values the actual result type does matter for t template.query(Person.class) <1> .distinct("lastname") <2> .all(); <3> ---- +---- <1> Query the collection of `Person`. <2> Select _distinct_ values of the `lastname` field. The fieldname will be mapped according to the domain types property declaration, taking potential `@Field` annotations into account. <3> Retrieve all distinct values as `List` of `Object` due to no explicit result type specification. ==== -Retrieving distinct values into a `Collection` of `Object.class` is the most flexible way as it will try to determine the property value of the domain type converting results to the desired type or mapping `Document` structures. +Retrieving distinct values into a `Collection` of `Object` is the most flexible way as it will try to determine the property value of the domain type converting results to the desired type or mapping `Document` structures. Sometimes, when all values of the desired field are fixed to a certain type, it is more convenient to directly obtain a correctly typed `Collection` @@ -1118,12 +1119,12 @@ template.query(Person.class) <1> .distinct("lastname") <2> .as(String.class) <3> .all(); <4> ---- +---- <1> Query the collection of `Person`. <2> Select _distinct_ values of the `lastname` field. The fieldname will be mapped according to the domain types property declaration, taking potential `@Field` annotations into account. <3> Retrieved values will be converted into the desired target type. In this case `String`. It would also be possible to map the values to a more complex type if the stored field contains a document. <4> Retrieve all distinct values as a `List` of `String`. Throws a `DataAccessException` if the type cannot be converted into the desired target type. -=== +==== [[mongo.geospatial]] === GeoSpatial Queries