From 6531bc792bb6518587c8e2dc37938887f60c6738 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 14 Apr 2025 11:32:34 +0200 Subject: [PATCH] Remove MongoDB driver 4 compatibility. Closes: #4886 --- .../data/mongodb/core/IndexConverters.java | 5 - .../core/MongoClientSettingsFactoryBean.java | 18 - .../data/mongodb/core/MongoTemplate.java | 10 +- .../mongodb/core/ReactiveMongoTemplate.java | 9 +- .../encryption/MongoClientEncryption.java | 4 +- .../mongodb/core/index/GeoSpatialIndexed.java | 10 - .../mongodb/core/index/GeospatialIndex.java | 18 - .../MongoPersistentEntityIndexResolver.java | 19 - .../core/mapreduce/MapReduceOptions.java | 19 - ...aultMongoHandlerObservationConvention.java | 13 - .../util/MongoCompatibilityAdapter.java | 417 ------------------ ...iveSessionBoundMongoTemplateUnitTests.java | 4 +- .../SessionBoundMongoTemplateUnitTests.java | 3 +- ...ersistentEntityIndexResolverUnitTests.java | 6 +- .../mongodb/core/query/IndexUnitTests.java | 4 +- .../mongodb/test/util/CleanMongoDBTests.java | 6 +- .../mongodb/test/util/MongoTestTemplate.java | 3 +- .../MongoCompatibilityAdapterUnitTests.java | 49 -- 18 files changed, 15 insertions(+), 602 deletions(-) delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java delete mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapterUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java index f5856100d..2008b85f6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/IndexConverters.java @@ -18,11 +18,9 @@ package org.springframework.data.mongodb.core; import java.util.concurrent.TimeUnit; import org.bson.Document; - import org.springframework.core.convert.converter.Converter; import org.springframework.data.mongodb.core.index.IndexDefinition; import org.springframework.data.mongodb.core.index.IndexInfo; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; @@ -90,9 +88,6 @@ abstract class IndexConverters { if (indexOptions.containsKey("bits")) { ops = ops.bits((Integer) indexOptions.get("bits")); } - if (indexOptions.containsKey("bucketSize")) { - MongoCompatibilityAdapter.indexOptionsAdapter(ops).setBucketSize(((Number) indexOptions.get("bucketSize")).doubleValue()); - } if (indexOptions.containsKey("default_language")) { ops = ops.defaultLanguage(indexOptions.get("default_language").toString()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientSettingsFactoryBean.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientSettingsFactoryBean.java index 02913b430..4400db1ea 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientSettingsFactoryBean.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoClientSettingsFactoryBean.java @@ -25,9 +25,7 @@ import javax.net.ssl.SSLContext; import org.bson.UuidRepresentation; import org.bson.codecs.configuration.CodecRegistry; - import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -57,8 +55,6 @@ public class MongoClientSettingsFactoryBean extends AbstractFactoryBean { - for (String name : MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db).listCollectionNames()) { + for (String name : db.listCollectionNames()) { if (name.equals(collectionName)) { return true; } @@ -1980,11 +1979,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, mapReduce = mapReduce.jsMode(mapReduceOptions.getJavaScriptMode()); } - if (mapReduceOptions.getOutputSharded().isPresent()) { - MongoCompatibilityAdapter.mapReduceIterableAdapter(mapReduce) - .sharded(mapReduceOptions.getOutputSharded().get()); - } - if (StringUtils.hasText(mapReduceOptions.getOutputCollection()) && !mapReduceOptions.usesInlineOutput()) { mapReduce = mapReduce.collectionName(mapReduceOptions.getOutputCollection()) @@ -2367,7 +2361,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, public Set getCollectionNames() { return execute(db -> { Set result = new LinkedHashSet<>(); - for (String name : MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db).listCollectionNames()) { + for (String name : db.listCollectionNames()) { result.add(name); } return result; 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 b74ec6aa1..9b5af77f6 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 @@ -118,7 +118,6 @@ import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import org.springframework.data.projection.EntityProjection; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; @@ -739,7 +738,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @Override public Mono collectionExists(String collectionName) { - return createMono(db -> Flux.from(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(db).listCollectionNames()) // + return createMono(db -> Flux.from(db.listCollectionNames()) // .filter(s -> s.equals(collectionName)) // .map(s -> true) // .single(false)); @@ -787,7 +786,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @Override public Flux getCollectionNames() { - return createFlux(db -> MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(db).listCollectionNames()); + return createFlux(db -> db.listCollectionNames()); } public Mono getMongoDatabase() { @@ -2176,10 +2175,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati publisher = publisher.jsMode(options.getJavaScriptMode()); } - if (options.getOutputSharded().isPresent()) { - MongoCompatibilityAdapter.mapReducePublisherAdapter(publisher).sharded(options.getOutputSharded().get()); - } - if (StringUtils.hasText(options.getOutputCollection()) && !options.usesInlineOutput()) { publisher = publisher.collectionName(options.getOutputCollection()).action(options.getMapReduceAction()); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/encryption/MongoClientEncryption.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/encryption/MongoClientEncryption.java index f83f98d4a..aee5dd7f8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/encryption/MongoClientEncryption.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/encryption/MongoClientEncryption.java @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.core.encryption; -import static org.springframework.data.mongodb.util.MongoCompatibilityAdapter.rangeOptionsAdapter; - import java.util.Map; import java.util.function.Supplier; @@ -124,7 +122,7 @@ public class MongoClientEncryption implements Encryption Assert.isInstanceOf(Integer.class, trimFactor, () -> String .format("Expected to find a %s but it turned out to be %s.", Integer.class, trimFactor.getClass())); - rangeOptionsAdapter(encryptionRangeOptions).trimFactor((Integer) trimFactor); + encryptionRangeOptions.trimFactor((Integer) trimFactor); } if (attributes.containsKey("sparsity")) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java index 3fb797559..a39da5c94 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java @@ -114,16 +114,6 @@ public @interface GeoSpatialIndexed { */ GeoSpatialIndexType type() default GeoSpatialIndexType.GEO_2D; - /** - * The bucket size for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes, in coordinate units. - * - * @since 1.4 - * @return {@literal 1.0} by default. - * @deprecated since MongoDB server version 4.4 - */ - @Deprecated - double bucketSize() default 1.0; - /** * The name of the additional field to use for {@link GeoSpatialIndexType#GEO_HAYSTACK} indexes * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeospatialIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeospatialIndex.java index 094950619..1c5a8ca6b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeospatialIndex.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeospatialIndex.java @@ -19,7 +19,6 @@ import java.util.Optional; import org.bson.Document; import org.springframework.data.mongodb.core.query.Collation; -import org.springframework.data.mongodb.util.MongoClientVersion; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -41,7 +40,6 @@ public class GeospatialIndex implements IndexDefinition { private @Nullable Integer max; private @Nullable Integer bits; private GeoSpatialIndexType type = GeoSpatialIndexType.GEO_2D; - private Double bucketSize = MongoClientVersion.isVersion5orNewer() ? null : 1.0; private @Nullable String additionalField; private Optional filter = Optional.empty(); private Optional collation = Optional.empty(); @@ -107,17 +105,6 @@ public class GeospatialIndex implements IndexDefinition { return this; } - /** - * @param bucketSize - * @return this. - * @deprecated since MongoDB server version 4.4 - */ - @Deprecated - public GeospatialIndex withBucketSize(double bucketSize) { - this.bucketSize = bucketSize; - return this; - } - /** * @param fieldName * @return this. @@ -203,14 +190,9 @@ public class GeospatialIndex implements IndexDefinition { break; case GEO_2DSPHERE: - break; case GEO_HAYSTACK: - - if (bucketSize != null) { - document.put("bucketSize", bucketSize); - } break; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java index a5988b8c1..37008ad76 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java @@ -25,7 +25,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -55,7 +54,6 @@ import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.util.BsonUtils; import org.springframework.data.mongodb.util.DotPath; import org.springframework.data.mongodb.util.DurationUtil; -import org.springframework.data.mongodb.util.MongoClientVersion; import org.springframework.data.mongodb.util.spel.ExpressionUtils; import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.data.util.TypeInformation; @@ -711,23 +709,6 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { .named(pathAwareIndexName(index.name(), dotPath, persistentProperty.getOwner(), persistentProperty)); } - if (MongoClientVersion.isVersion5orNewer()) { - - Optional defaultBucketSize = MergedAnnotation.of(GeoSpatialIndexed.class).getDefaultValue("bucketSize", - Double.class); - if (!defaultBucketSize.isPresent() || index.bucketSize() != defaultBucketSize.get()) { - indexDefinition.withBucketSize(index.bucketSize()); - } else { - if (LOGGER.isInfoEnabled()) { - LOGGER.info( - "GeoSpatialIndexed.bucketSize no longer supported by Mongo Client 5 or newer. Ignoring bucketSize for path %s." - .formatted(dotPath)); - } - } - } else { - indexDefinition.withBucketSize(index.bucketSize()); - } - indexDefinition.typed(index.type()).withAdditionalField(index.additionalField()); return new IndexDefinitionHolder(dotPath, indexDefinition, collection); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java index 9f34ec44e..e9ee146be 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapreduce/MapReduceOptions.java @@ -45,7 +45,6 @@ public class MapReduceOptions { private Boolean verbose = Boolean.TRUE; private @Nullable Integer limit; - private Optional outputSharded = Optional.empty(); private Optional finalizeFunction = Optional.empty(); private Optional collation = Optional.empty(); @@ -152,19 +151,6 @@ public class MapReduceOptions { return this; } - /** - * If true and combined with an output mode that writes to a collection, the output collection will be sharded using - * the _id field. For MongoDB 1.9+ - * - * @param outputShared if true, output will be sharded based on _id key. - * @return MapReduceOptions so that methods can be chained in a fluent API style - */ - public MapReduceOptions outputSharded(boolean outputShared) { - - this.outputSharded = Optional.of(outputShared); - return this; - } - /** * Sets the finalize function * @@ -245,10 +231,6 @@ public class MapReduceOptions { return this.outputDatabase; } - public Optional getOutputSharded() { - return this.outputSharded; - } - public Map getScopeVariables() { return this.scopeVariables; } @@ -336,7 +318,6 @@ public class MapReduceOptions { } outputDatabase.ifPresent(val -> out.append("db", val)); - outputSharded.ifPresent(val -> out.append("sharded", val)); return out; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/DefaultMongoHandlerObservationConvention.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/DefaultMongoHandlerObservationConvention.java index b823ce223..8c7c6a55c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/DefaultMongoHandlerObservationConvention.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/DefaultMongoHandlerObservationConvention.java @@ -17,10 +17,7 @@ package org.springframework.data.mongodb.observability; import io.micrometer.common.KeyValues; -import java.net.InetSocketAddress; - import org.springframework.data.mongodb.observability.MongoObservation.LowCardinalityCommandKeyNames; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import org.springframework.util.ObjectUtils; import com.mongodb.ConnectionString; @@ -78,16 +75,6 @@ class DefaultMongoHandlerObservationConvention implements MongoHandlerObservatio keyValues = keyValues.and(LowCardinalityCommandKeyNames.NET_TRANSPORT.withValue("IP.TCP"), LowCardinalityCommandKeyNames.NET_PEER_NAME.withValue(serverAddress.getHost()), LowCardinalityCommandKeyNames.NET_PEER_PORT.withValue("" + serverAddress.getPort())); - - InetSocketAddress socketAddress = MongoCompatibilityAdapter.serverAddressAdapter(serverAddress) - .getSocketAddress(); - - if (socketAddress != null) { - - keyValues = keyValues.and( - LowCardinalityCommandKeyNames.NET_SOCK_PEER_ADDR.withValue(socketAddress.getHostName()), - LowCardinalityCommandKeyNames.NET_SOCK_PEER_PORT.withValue("" + socketAddress.getPort())); - } } ConnectionId connectionId = connectionDescription.getConnectionId(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java deleted file mode 100644 index 8bd422c49..000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright 2024-2025 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 - * - * https://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.util; - -import java.lang.reflect.Method; -import java.net.InetSocketAddress; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.reactivestreams.Publisher; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; - -import com.mongodb.MongoClientSettings; -import com.mongodb.MongoClientSettings.Builder; -import com.mongodb.ServerAddress; -import com.mongodb.client.ClientSession; -import com.mongodb.client.MapReduceIterable; -import com.mongodb.client.MongoDatabase; -import com.mongodb.client.MongoIterable; -import com.mongodb.client.model.IndexOptions; -import com.mongodb.client.model.vault.RangeOptions; -import com.mongodb.reactivestreams.client.MapReducePublisher; - -/** - * Compatibility adapter to bridge functionality across different MongoDB driver versions. - *

- * This class is for internal use within the framework and should not be used by applications. - * - * @author Christoph Strobl - * @author Ross Lawley - * @since 4.3 - */ -public class MongoCompatibilityAdapter { - - private static final String NO_LONGER_SUPPORTED = "%s is no longer supported on Mongo Client 5 or newer"; - private static final String NOT_SUPPORTED_ON_4 = "%s is not supported on Mongo Client 4"; - - private static final @Nullable Method getStreamFactoryFactory = ReflectionUtils.findMethod(MongoClientSettings.class, - "getStreamFactoryFactory"); - - private static final @Nullable Method setBucketSize = ReflectionUtils.findMethod(IndexOptions.class, "bucketSize", - Double.class); - - private static final @Nullable Method setTrimFactor; - - static { - - // method name changed in between - Method trimFactor = ReflectionUtils.findMethod(RangeOptions.class, "setTrimFactor", Integer.class); - if (trimFactor != null) { - setTrimFactor = trimFactor; - } else { - setTrimFactor = ReflectionUtils.findMethod(RangeOptions.class, "trimFactor", Integer.class); - } - } - - /** - * Return a compatibility adapter for {@link MongoClientSettings.Builder}. - * - * @param builder - * @return - */ - public static ClientSettingsBuilderAdapter clientSettingsBuilderAdapter(MongoClientSettings.Builder builder) { - return new MongoStreamFactoryFactorySettingsConfigurer(builder)::setStreamFactory; - } - - /** - * Return a compatibility adapter for {@link MongoClientSettings}. - * - * @param clientSettings - * @return - */ - public static ClientSettingsAdapter clientSettingsAdapter(MongoClientSettings clientSettings) { - return new ClientSettingsAdapter() { - @Override - public T getStreamFactoryFactory() { - - if (MongoClientVersion.isVersion5orNewer() || getStreamFactoryFactory == null) { - return null; - } - - return (T) ReflectionUtils.invokeMethod(getStreamFactoryFactory, clientSettings); - } - }; - } - - /** - * Return a compatibility adapter for {@link IndexOptions}. - * - * @param options - * @return - */ - public static IndexOptionsAdapter indexOptionsAdapter(IndexOptions options) { - return bucketSize -> { - - if (MongoClientVersion.isVersion5orNewer() || setBucketSize == null) { - throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("IndexOptions.bucketSize")); - } - - ReflectionUtils.invokeMethod(setBucketSize, options, bucketSize); - }; - } - - /** - * Return a compatibility adapter for {@code MapReduceIterable}. - * - * @param iterable - * @return - */ - @SuppressWarnings("deprecation") - public static MapReduceIterableAdapter mapReduceIterableAdapter(Object iterable) { - return sharded -> { - - if (MongoClientVersion.isVersion5orNewer()) { - throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("sharded")); - } - - // Use MapReduceIterable to avoid package-protected access violations to - // com.mongodb.client.internal.MapReduceIterableImpl - Method shardedMethod = ReflectionUtils.findMethod(MapReduceIterable.class, "sharded", boolean.class); - ReflectionUtils.invokeMethod(shardedMethod, iterable, sharded); - }; - } - - /** - * Return a compatibility adapter for {@link RangeOptions}. - * - * @param options - * @return - */ - public static RangeOptionsAdapter rangeOptionsAdapter(RangeOptions options) { - return trimFactor -> { - - if (!MongoClientVersion.isVersion5orNewer() || setTrimFactor == null) { - throw new UnsupportedOperationException(NOT_SUPPORTED_ON_4.formatted("RangeOptions.trimFactor")); - } - - ReflectionUtils.invokeMethod(setTrimFactor, options, trimFactor); - }; - } - - /** - * Return a compatibility adapter for {@code MapReducePublisher}. - * - * @param publisher - * @return - */ - @SuppressWarnings("deprecation") - public static MapReducePublisherAdapter mapReducePublisherAdapter(Object publisher) { - return sharded -> { - - if (MongoClientVersion.isVersion5orNewer()) { - throw new UnsupportedOperationException(NO_LONGER_SUPPORTED.formatted("sharded")); - } - - // Use MapReducePublisher to avoid package-protected access violations to MapReducePublisherImpl - Method shardedMethod = ReflectionUtils.findMethod(MapReducePublisher.class, "sharded", boolean.class); - ReflectionUtils.invokeMethod(shardedMethod, publisher, sharded); - }; - } - - /** - * Return a compatibility adapter for {@link ServerAddress}. - * - * @param serverAddress - * @return - */ - public static ServerAddressAdapter serverAddressAdapter(ServerAddress serverAddress) { - return () -> { - - if (MongoClientVersion.isVersion5orNewer()) { - return null; - } - - Method serverAddressMethod = ReflectionUtils.findMethod(ServerAddress.class, "getSocketAddress"); - Object value = ReflectionUtils.invokeMethod(serverAddressMethod, serverAddress); - return value != null ? InetSocketAddress.class.cast(value) : null; - }; - } - - public static MongoDatabaseAdapterBuilder mongoDatabaseAdapter() { - return MongoDatabaseAdapter::new; - } - - public static ReactiveMongoDatabaseAdapterBuilder reactiveMongoDatabaseAdapter() { - return ReactiveMongoDatabaseAdapter::new; - } - - public interface IndexOptionsAdapter { - void setBucketSize(double bucketSize); - } - - public interface ClientSettingsAdapter { - @Nullable - T getStreamFactoryFactory(); - } - - public interface ClientSettingsBuilderAdapter { - void setStreamFactoryFactory(T streamFactory); - } - - public interface MapReduceIterableAdapter { - void sharded(boolean sharded); - } - - public interface MapReducePublisherAdapter { - void sharded(boolean sharded); - } - - public interface ServerAddressAdapter { - @Nullable - InetSocketAddress getSocketAddress(); - } - - public interface MongoDatabaseAdapterBuilder { - MongoDatabaseAdapter forDb(com.mongodb.client.MongoDatabase db); - } - - public interface RangeOptionsAdapter { - void trimFactor(Integer trimFactor); - } - - @SuppressWarnings({ "unchecked", "DataFlowIssue" }) - public static class MongoDatabaseAdapter { - - @Nullable // - private static final Method LIST_COLLECTION_NAMES_METHOD; - - @Nullable // - private static final Method LIST_COLLECTION_NAMES_METHOD_SESSION; - - private static final Class collectionNamesReturnType; - - private final MongoDatabase db; - - static { - - if (MongoClientVersion.isSyncClientPresent()) { - - LIST_COLLECTION_NAMES_METHOD = ReflectionUtils.findMethod(MongoDatabase.class, "listCollectionNames"); - LIST_COLLECTION_NAMES_METHOD_SESSION = ReflectionUtils.findMethod(MongoDatabase.class, "listCollectionNames", - ClientSession.class); - - if (MongoClientVersion.isVersion5orNewer()) { - try { - collectionNamesReturnType = ClassUtils.forName("com.mongodb.client.ListCollectionNamesIterable", - MongoDatabaseAdapter.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Unable to load com.mongodb.client.ListCollectionNamesIterable", e); - } - } else { - try { - collectionNamesReturnType = ClassUtils.forName("com.mongodb.client.MongoIterable", - MongoDatabaseAdapter.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Unable to load com.mongodb.client.ListCollectionNamesIterable", e); - } - } - } else { - LIST_COLLECTION_NAMES_METHOD = null; - LIST_COLLECTION_NAMES_METHOD_SESSION = null; - collectionNamesReturnType = Object.class; - } - } - - public MongoDatabaseAdapter(MongoDatabase db) { - this.db = db; - } - - public Class> collectionNameIterableType() { - return (Class>) collectionNamesReturnType; - } - - public MongoIterable listCollectionNames() { - - Assert.state(LIST_COLLECTION_NAMES_METHOD != null, "No method listCollectionNames present for %s".formatted(db)); - return (MongoIterable) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD, db); - } - - public MongoIterable listCollectionNames(ClientSession clientSession) { - Assert.state(LIST_COLLECTION_NAMES_METHOD != null, - "No method listCollectionNames(ClientSession) present for %s".formatted(db)); - return (MongoIterable) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD_SESSION, db, - clientSession); - } - } - - public interface ReactiveMongoDatabaseAdapterBuilder { - ReactiveMongoDatabaseAdapter forDb(com.mongodb.reactivestreams.client.MongoDatabase db); - } - - @SuppressWarnings({ "unchecked", "DataFlowIssue" }) - public static class ReactiveMongoDatabaseAdapter { - - @Nullable // - private static final Method LIST_COLLECTION_NAMES_METHOD; - - @Nullable // - private static final Method LIST_COLLECTION_NAMES_METHOD_SESSION; - - private static final Class collectionNamesReturnType; - - private final com.mongodb.reactivestreams.client.MongoDatabase db; - - static { - - if (MongoClientVersion.isReactiveClientPresent()) { - - LIST_COLLECTION_NAMES_METHOD = ReflectionUtils - .findMethod(com.mongodb.reactivestreams.client.MongoDatabase.class, "listCollectionNames"); - LIST_COLLECTION_NAMES_METHOD_SESSION = ReflectionUtils.findMethod( - com.mongodb.reactivestreams.client.MongoDatabase.class, "listCollectionNames", - com.mongodb.reactivestreams.client.ClientSession.class); - - if (MongoClientVersion.isVersion5orNewer()) { - try { - collectionNamesReturnType = ClassUtils.forName( - "com.mongodb.reactivestreams.client.ListCollectionNamesPublisher", - ReactiveMongoDatabaseAdapter.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("com.mongodb.reactivestreams.client.ListCollectionNamesPublisher", e); - } - } else { - try { - collectionNamesReturnType = ClassUtils.forName("org.reactivestreams.Publisher", - ReactiveMongoDatabaseAdapter.class.getClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException("org.reactivestreams.Publisher", e); - } - } - } else { - LIST_COLLECTION_NAMES_METHOD = null; - LIST_COLLECTION_NAMES_METHOD_SESSION = null; - collectionNamesReturnType = Object.class; - } - } - - ReactiveMongoDatabaseAdapter(com.mongodb.reactivestreams.client.MongoDatabase db) { - this.db = db; - } - - public Class> collectionNamePublisherType() { - return (Class>) collectionNamesReturnType; - - } - - public Publisher listCollectionNames() { - Assert.state(LIST_COLLECTION_NAMES_METHOD != null, "No method listCollectionNames present for %s".formatted(db)); - return (Publisher) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD, db); - } - - public Publisher listCollectionNames(com.mongodb.reactivestreams.client.ClientSession clientSession) { - Assert.state(LIST_COLLECTION_NAMES_METHOD != null, - "No method listCollectionNames(ClientSession) present for %s".formatted(db)); - return (Publisher) ReflectionUtils.invokeMethod(LIST_COLLECTION_NAMES_METHOD_SESSION, db, clientSession); - } - } - - static class MongoStreamFactoryFactorySettingsConfigurer { - - private static final Log logger = LogFactory.getLog(MongoStreamFactoryFactorySettingsConfigurer.class); - - private static final String STREAM_FACTORY_NAME = "com.mongodb.connection.StreamFactoryFactory"; - private static final boolean STREAM_FACTORY_PRESENT = ClassUtils.isPresent(STREAM_FACTORY_NAME, - MongoCompatibilityAdapter.class.getClassLoader()); - private final MongoClientSettings.Builder settingsBuilder; - - static boolean isStreamFactoryPresent() { - return STREAM_FACTORY_PRESENT; - } - - public MongoStreamFactoryFactorySettingsConfigurer(Builder settingsBuilder) { - this.settingsBuilder = settingsBuilder; - } - - void setStreamFactory(Object streamFactory) { - - if (MongoClientVersion.isVersion5orNewer() && isStreamFactoryPresent()) { - logger.warn("StreamFactoryFactory is no longer available. Use TransportSettings instead."); - return; - } - - try { - Class streamFactoryType = ClassUtils.forName(STREAM_FACTORY_NAME, streamFactory.getClass().getClassLoader()); - - if (!ClassUtils.isAssignable(streamFactoryType, streamFactory.getClass())) { - throw new IllegalArgumentException("Expected %s but found %s".formatted(streamFactoryType, streamFactory)); - } - - Method setter = ReflectionUtils.findMethod(settingsBuilder.getClass(), "streamFactoryFactory", - streamFactoryType); - if (setter != null) { - ReflectionUtils.invokeMethod(setter, settingsBuilder, streamFactoryType.cast(streamFactory)); - } - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException("Cannot set StreamFactoryFactory for %s".formatted(settingsBuilder), e); - } - } - } - -} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveSessionBoundMongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveSessionBoundMongoTemplateUnitTests.java index 73970d2ad..02637e997 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveSessionBoundMongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveSessionBoundMongoTemplateUnitTests.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.*; import java.lang.reflect.Proxy; +import com.mongodb.reactivestreams.client.ListCollectionNamesPublisher; import org.bson.Document; import org.bson.codecs.BsonValueCodec; import org.bson.codecs.configuration.CodecRegistry; @@ -58,7 +59,6 @@ import com.mongodb.reactivestreams.client.MapReducePublisher; import com.mongodb.reactivestreams.client.MongoClient; import com.mongodb.reactivestreams.client.MongoCollection; import com.mongodb.reactivestreams.client.MongoDatabase; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; /** * Unit tests for {@link ReactiveSessionBoundMongoTemplate}. @@ -94,7 +94,7 @@ public class ReactiveSessionBoundMongoTemplateUnitTests { @Before public void setUp() { - mock(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(database).collectionNamePublisherType()); + mock(ListCollectionNamesPublisher.class); when(client.getDatabase(anyString())).thenReturn(database); when(codecRegistry.get(any(Class.class))).thenReturn(new BsonValueCodec()); when(database.getCodecRegistry()).thenReturn(codecRegistry); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SessionBoundMongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SessionBoundMongoTemplateUnitTests.java index dfa4b0051..50ea57904 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SessionBoundMongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SessionBoundMongoTemplateUnitTests.java @@ -49,7 +49,6 @@ import com.mongodb.client.model.CountOptions; import com.mongodb.client.model.DeleteOptions; import com.mongodb.client.model.FindOneAndUpdateOptions; import com.mongodb.client.model.UpdateOptions; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; /** * Unit test for {@link SessionBoundMongoTemplate} making sure a proxied {@link MongoCollection} and @@ -90,7 +89,7 @@ public class SessionBoundMongoTemplateUnitTests { @Before public void setUp() { - collectionNamesIterable = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(database).collectionNameIterableType()); + collectionNamesIterable = mock(ListCollectionNamesIterable.class); when(client.getDatabase(anyString())).thenReturn(database); when(codecRegistry.get(any(Class.class))).thenReturn(new BsonValueCodec()); when(database.getCodecRegistry()).thenReturn(codecRegistry); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java index d1fa2b1b9..dda16f784 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java @@ -31,7 +31,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; - import org.springframework.core.annotation.AliasFor; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.annotation.Id; @@ -506,7 +505,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { assertThat(indexDefinition.getIndexKeys()).containsEntry("location", "geoHaystack").containsEntry("What light?", 1); assertThat(indexDefinition.getIndexOptions()).containsEntry("name", "my_geo_index_name") - .containsEntry("bucketSize", 2.0); + .doesNotContainKey("bucketSize"); } @Test // DATAMONGO-2112 @@ -558,9 +557,6 @@ public class MongoPersistentEntityIndexResolverUnitTests { @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "additionalField") String theAdditionalFieldINeedToDefine() default "What light?"; - @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "bucketSize") - double size() default 2; - @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "type") GeoSpatialIndexType indexType() default GeoSpatialIndexType.GEO_HAYSTACK; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/IndexUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/IndexUnitTests.java index 156b5b23c..2ec31e49b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/IndexUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/IndexUnitTests.java @@ -80,9 +80,9 @@ public class IndexUnitTests { public void testGeospatialIndexGeoHaystack() { GeospatialIndex i = new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_HAYSTACK) - .withAdditionalField("name").withBucketSize(40); + .withAdditionalField("name"); assertThat(i.getIndexKeys()).isEqualTo(Document.parse("{ \"location\" : \"geoHaystack\" , \"name\" : 1}")); - assertThat(i.getIndexOptions()).isEqualTo(Document.parse("{ \"bucketSize\" : 40.0}")); + assertThat(i.getIndexOptions()).isEqualTo(Document.parse("{ }")); } @Test diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/CleanMongoDBTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/CleanMongoDBTests.java index f2fd993ef..17a045b7a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/CleanMongoDBTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/CleanMongoDBTests.java @@ -32,8 +32,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import org.springframework.data.mongodb.test.util.CleanMongoDB.Struct; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; +import com.mongodb.client.ListCollectionNamesIterable; import com.mongodb.client.ListDatabasesIterable; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; @@ -74,11 +74,11 @@ class CleanMongoDBTests { when(mongoClientMock.getDatabase(eq("db2"))).thenReturn(db2mock); // collections have to exist - MongoIterable collectionIterable = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db1mock).collectionNameIterableType()); + MongoIterable collectionIterable = mock(ListCollectionNamesIterable.class); when(collectionIterable.into(any(Collection.class))).thenReturn(Arrays.asList("db1collection1", "db1collection2")); doReturn(collectionIterable).when(db1mock).listCollectionNames(); - MongoIterable collectionIterable2 = mock(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(db2mock).collectionNameIterableType()); + MongoIterable collectionIterable2 = mock(ListCollectionNamesIterable.class); when(collectionIterable2.into(any(Collection.class))).thenReturn(Collections.singletonList("db2collection1")); doReturn(collectionIterable2).when(db2mock).listCollectionNames(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java index 40948a0e2..53bd7c6ab 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/test/util/MongoTestTemplate.java @@ -28,7 +28,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.util.MongoCompatibilityAdapter; import org.testcontainers.shaded.org.awaitility.Awaitility; import com.mongodb.MongoWriteException; @@ -96,7 +95,7 @@ public class MongoTestTemplate extends MongoTemplate { } public void flushDatabase() { - flush(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(getDb()).listCollectionNames()); + flush(getDb().listCollectionNames()); } public void flush(Iterable collections) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapterUnitTests.java deleted file mode 100644 index ab8e17a46..000000000 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapterUnitTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2024-2025 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 - * - * https://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.util; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Test; -import org.springframework.data.mongodb.test.util.ExcludeReactiveClientFromClassPath; -import org.springframework.data.mongodb.test.util.ExcludeSyncClientFromClassPath; -import org.springframework.util.ClassUtils; - -/** - * @author Christoph Strobl - */ -class MongoCompatibilityAdapterUnitTests { - - @Test // GH-4578 - @ExcludeReactiveClientFromClassPath - void returnsListCollectionNameIterableTypeCorrectly() { - - String expectedType = MongoClientVersion.isVersion5orNewer() ? "ListCollectionNamesIterable" : "MongoIterable"; - assertThat(MongoCompatibilityAdapter.mongoDatabaseAdapter().forDb(null).collectionNameIterableType()) - .satisfies(type -> assertThat(ClassUtils.getShortName(type)).isEqualTo(expectedType)); - - } - - @Test // GH-4578 - @ExcludeSyncClientFromClassPath - void returnsListCollectionNamePublisherTypeCorrectly() { - - String expectedType = MongoClientVersion.isVersion5orNewer() ? "ListCollectionNamesPublisher" : "Publisher"; - assertThat(MongoCompatibilityAdapter.reactiveMongoDatabaseAdapter().forDb(null).collectionNamePublisherType()) - .satisfies(type -> assertThat(ClassUtils.getShortName(type)).isEqualTo(expectedType)); - - } -}