Create spring-boot-mongodb module
This commit is contained in:
committed by
Phillip Webb
parent
65a50949d8
commit
254f901f14
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.client.MongoClient;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Mongo.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Oliver Gierke
|
||||
* @author Phillip Webb
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass(MongoClient.class)
|
||||
@EnableConfigurationProperties(MongoProperties.class)
|
||||
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDatabaseFactory")
|
||||
public class MongoAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(MongoConnectionDetails.class)
|
||||
PropertiesMongoConnectionDetails mongoConnectionDetails(MongoProperties properties,
|
||||
ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesMongoConnectionDetails(properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MongoClient mongo(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers,
|
||||
MongoClientSettings settings) {
|
||||
return new MongoClientFactory(builderCustomizers.orderedStream().toList()).createMongoClient(settings);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(MongoClientSettings.class)
|
||||
static class MongoClientSettingsConfiguration {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings() {
|
||||
return MongoClientSettings.builder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
StandardMongoClientSettingsBuilderCustomizer standardMongoSettingsCustomizer(MongoProperties properties,
|
||||
MongoConnectionDetails connectionDetails) {
|
||||
return new StandardMongoClientSettingsBuilderCustomizer(connectionDetails,
|
||||
properties.getUuidRepresentation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
||||
/**
|
||||
* A factory for a blocking {@link MongoClient}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
* @author Andy Wilkinson
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Nasko Vasilev
|
||||
* @author Mark Paluch
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class MongoClientFactory extends MongoClientFactorySupport<MongoClient> {
|
||||
|
||||
/**
|
||||
* Construct a factory for creating a blocking {@link MongoClient}.
|
||||
* @param builderCustomizers a list of configuration settings customizers
|
||||
*/
|
||||
public MongoClientFactory(List<MongoClientSettingsBuilderCustomizer> builderCustomizers) {
|
||||
super(builderCustomizers, MongoClients::create);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoClientSettings.Builder;
|
||||
import com.mongodb.MongoDriverInformation;
|
||||
|
||||
/**
|
||||
* Base class for setup that is common to MongoDB client factories.
|
||||
*
|
||||
* @param <T> the mongo client type
|
||||
* @author Christoph Strobl
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public abstract class MongoClientFactorySupport<T> {
|
||||
|
||||
private final List<MongoClientSettingsBuilderCustomizer> builderCustomizers;
|
||||
|
||||
private final BiFunction<MongoClientSettings, MongoDriverInformation, T> clientCreator;
|
||||
|
||||
protected MongoClientFactorySupport(List<MongoClientSettingsBuilderCustomizer> builderCustomizers,
|
||||
BiFunction<MongoClientSettings, MongoDriverInformation, T> clientCreator) {
|
||||
this.builderCustomizers = (builderCustomizers != null) ? builderCustomizers : Collections.emptyList();
|
||||
this.clientCreator = clientCreator;
|
||||
}
|
||||
|
||||
public T createMongoClient(MongoClientSettings settings) {
|
||||
Builder targetSettings = MongoClientSettings.builder(settings);
|
||||
customize(targetSettings);
|
||||
return this.clientCreator.apply(targetSettings.build(), driverInformation());
|
||||
}
|
||||
|
||||
private void customize(Builder builder) {
|
||||
for (MongoClientSettingsBuilderCustomizer customizer : this.builderCustomizers) {
|
||||
customizer.customize(builder);
|
||||
}
|
||||
}
|
||||
|
||||
private MongoDriverInformation driverInformation() {
|
||||
return MongoDriverInformation.builder(MongoDriverInformation.builder().build())
|
||||
.driverName("spring-boot")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import com.mongodb.MongoClientSettings.Builder;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link com.mongodb.MongoClientSettings} through a {@link Builder
|
||||
* MongoClientSettings.Builder} whilst retaining default auto-configuration.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MongoClientSettingsBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link Builder}.
|
||||
* @param clientSettingsBuilder the builder to customize
|
||||
*/
|
||||
void customize(Builder clientSettingsBuilder);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
/**
|
||||
* Details required to establish a connection to a MongoDB service.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public interface MongoConnectionDetails extends ConnectionDetails {
|
||||
|
||||
/**
|
||||
* The {@link ConnectionString} for MongoDB.
|
||||
* @return the connection string
|
||||
*/
|
||||
ConnectionString getConnectionString();
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* GridFS configuration.
|
||||
* @return the GridFS configuration or {@code null}
|
||||
*/
|
||||
default GridFs getGridFs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* GridFS configuration.
|
||||
*/
|
||||
interface GridFs {
|
||||
|
||||
/**
|
||||
* GridFS database name.
|
||||
* @return the GridFS database name or {@code null}
|
||||
*/
|
||||
String getDatabase();
|
||||
|
||||
/**
|
||||
* GridFS bucket name.
|
||||
* @return the GridFS bucket name or {@code null}
|
||||
*/
|
||||
String getBucket();
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link GridFs} instance.
|
||||
* @param database the database
|
||||
* @param bucket the bucket name
|
||||
* @return a new {@link GridFs} instance
|
||||
*/
|
||||
static GridFs of(String database, String bucket) {
|
||||
return new GridFs() {
|
||||
|
||||
@Override
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBucket() {
|
||||
return bucket;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
import org.bson.UuidRepresentation;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for Mongo.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Josh Long
|
||||
* @author Andy Wilkinson
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Nasko Vasilev
|
||||
* @author Mark Paluch
|
||||
* @author Artsiom Yudovin
|
||||
* @author Safeer Ansari
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.data.mongodb")
|
||||
public class MongoProperties {
|
||||
|
||||
/**
|
||||
* Default port used when the configured port is {@code null}.
|
||||
*/
|
||||
public static final int DEFAULT_PORT = 27017;
|
||||
|
||||
/**
|
||||
* Default URI used when the configured URI is {@code null}.
|
||||
*/
|
||||
public static final String DEFAULT_URI = "mongodb://localhost/test";
|
||||
|
||||
/**
|
||||
* Protocol to be used for the MongoDB connection. Ignored if 'uri' is set.
|
||||
*/
|
||||
private String protocol = "mongodb";
|
||||
|
||||
/**
|
||||
* Mongo server host. Ignored if 'uri' is set.
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* Mongo server port. Ignored if 'uri' is set.
|
||||
*/
|
||||
private Integer port = null;
|
||||
|
||||
/**
|
||||
* Additional server hosts. Ignored if 'uri' is set or if 'host' is omitted.
|
||||
* Additional hosts will use the default mongo port of 27017. If you want to use a
|
||||
* different port you can use the "host:port" syntax.
|
||||
*/
|
||||
private List<String> additionalHosts;
|
||||
|
||||
/**
|
||||
* Mongo database URI. Overrides host, port, username, and password.
|
||||
*/
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* Database name. Overrides database in URI.
|
||||
*/
|
||||
private String database;
|
||||
|
||||
/**
|
||||
* Authentication database name.
|
||||
*/
|
||||
private String authenticationDatabase;
|
||||
|
||||
private final Gridfs gridfs = new Gridfs();
|
||||
|
||||
/**
|
||||
* Login user of the mongo server. Ignored if 'uri' is set.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Login password of the mongo server. Ignored if 'uri' is set.
|
||||
*/
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Required replica set name for the cluster. Ignored if 'uri' is set.
|
||||
*/
|
||||
private String replicaSetName;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the FieldNamingStrategy to use.
|
||||
*/
|
||||
private Class<?> fieldNamingStrategy;
|
||||
|
||||
/**
|
||||
* Representation to use when converting a UUID to a BSON binary value.
|
||||
*/
|
||||
private UuidRepresentation uuidRepresentation = UuidRepresentation.JAVA_LEGACY;
|
||||
|
||||
private final Ssl ssl = new Ssl();
|
||||
|
||||
/**
|
||||
* Whether to enable auto-index creation.
|
||||
*/
|
||||
private Boolean autoIndexCreation;
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return this.database;
|
||||
}
|
||||
|
||||
public void setDatabase(String database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public String getAuthenticationDatabase() {
|
||||
return this.authenticationDatabase;
|
||||
}
|
||||
|
||||
public void setAuthenticationDatabase(String authenticationDatabase) {
|
||||
this.authenticationDatabase = authenticationDatabase;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public char[] getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(char[] password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getReplicaSetName() {
|
||||
return this.replicaSetName;
|
||||
}
|
||||
|
||||
public void setReplicaSetName(String replicaSetName) {
|
||||
this.replicaSetName = replicaSetName;
|
||||
}
|
||||
|
||||
public Class<?> getFieldNamingStrategy() {
|
||||
return this.fieldNamingStrategy;
|
||||
}
|
||||
|
||||
public void setFieldNamingStrategy(Class<?> fieldNamingStrategy) {
|
||||
this.fieldNamingStrategy = fieldNamingStrategy;
|
||||
}
|
||||
|
||||
public UuidRepresentation getUuidRepresentation() {
|
||||
return this.uuidRepresentation;
|
||||
}
|
||||
|
||||
public void setUuidRepresentation(UuidRepresentation uuidRepresentation) {
|
||||
this.uuidRepresentation = uuidRepresentation;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String determineUri() {
|
||||
return (this.uri != null) ? this.uri : DEFAULT_URI;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Gridfs getGridfs() {
|
||||
return this.gridfs;
|
||||
}
|
||||
|
||||
public String getMongoClientDatabase() {
|
||||
if (this.database != null) {
|
||||
return this.database;
|
||||
}
|
||||
return new ConnectionString(determineUri()).getDatabase();
|
||||
}
|
||||
|
||||
public Boolean isAutoIndexCreation() {
|
||||
return this.autoIndexCreation;
|
||||
}
|
||||
|
||||
public void setAutoIndexCreation(Boolean autoIndexCreation) {
|
||||
this.autoIndexCreation = autoIndexCreation;
|
||||
}
|
||||
|
||||
public List<String> getAdditionalHosts() {
|
||||
return this.additionalHosts;
|
||||
}
|
||||
|
||||
public void setAdditionalHosts(List<String> additionalHosts) {
|
||||
this.additionalHosts = additionalHosts;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
return this.ssl;
|
||||
}
|
||||
|
||||
public static class Gridfs {
|
||||
|
||||
/**
|
||||
* GridFS database name.
|
||||
*/
|
||||
private String database;
|
||||
|
||||
/**
|
||||
* GridFS bucket name.
|
||||
*/
|
||||
private String bucket;
|
||||
|
||||
public String getDatabase() {
|
||||
return this.database;
|
||||
}
|
||||
|
||||
public void setDatabase(String database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public String getBucket() {
|
||||
return this.bucket;
|
||||
}
|
||||
|
||||
public void setBucket(String bucket) {
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Ssl {
|
||||
|
||||
/**
|
||||
* Whether to enable SSL support. Enabled automatically if "bundle" is provided
|
||||
* unless specified otherwise.
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* SSL bundle name.
|
||||
*/
|
||||
private String bundle;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (this.enabled != null) ? this.enabled : this.bundle != null;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBundle() {
|
||||
return this.bundle;
|
||||
}
|
||||
|
||||
public void setBundle(String bundle) {
|
||||
this.bundle = bundle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoClientSettings.Builder;
|
||||
import com.mongodb.connection.TransportSettings;
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Reactive Mongo.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ MongoClient.class, Flux.class })
|
||||
@EnableConfigurationProperties(MongoProperties.class)
|
||||
public class MongoReactiveAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(MongoConnectionDetails.class)
|
||||
PropertiesMongoConnectionDetails mongoConnectionDetails(MongoProperties properties,
|
||||
ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesMongoConnectionDetails(properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MongoClient reactiveStreamsMongoClient(
|
||||
ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers, MongoClientSettings settings) {
|
||||
ReactiveMongoClientFactory factory = new ReactiveMongoClientFactory(
|
||||
builderCustomizers.orderedStream().toList());
|
||||
return factory.createMongoClient(settings);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(MongoClientSettings.class)
|
||||
static class MongoClientSettingsConfiguration {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings() {
|
||||
return MongoClientSettings.builder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
StandardMongoClientSettingsBuilderCustomizer standardMongoSettingsCustomizer(MongoProperties properties,
|
||||
MongoConnectionDetails connectionDetails) {
|
||||
return new StandardMongoClientSettingsBuilderCustomizer(connectionDetails,
|
||||
properties.getUuidRepresentation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ SocketChannel.class, NioEventLoopGroup.class })
|
||||
static class NettyDriverConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
NettyDriverMongoClientSettingsBuilderCustomizer nettyDriverCustomizer(
|
||||
ObjectProvider<MongoClientSettings> settings) {
|
||||
return new NettyDriverMongoClientSettingsBuilderCustomizer(settings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MongoClientSettingsBuilderCustomizer} to apply Mongo client settings.
|
||||
*/
|
||||
static final class NettyDriverMongoClientSettingsBuilderCustomizer
|
||||
implements MongoClientSettingsBuilderCustomizer, DisposableBean {
|
||||
|
||||
private final ObjectProvider<MongoClientSettings> settings;
|
||||
|
||||
private volatile EventLoopGroup eventLoopGroup;
|
||||
|
||||
NettyDriverMongoClientSettingsBuilderCustomizer(ObjectProvider<MongoClientSettings> settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Builder builder) {
|
||||
if (!isCustomTransportConfiguration(this.settings.getIfAvailable())) {
|
||||
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
|
||||
this.eventLoopGroup = eventLoopGroup;
|
||||
builder.transportSettings(TransportSettings.nettyBuilder().eventLoopGroup(eventLoopGroup).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
EventLoopGroup eventLoopGroup = this.eventLoopGroup;
|
||||
if (eventLoopGroup != null) {
|
||||
eventLoopGroup.shutdownGracefully().awaitUninterruptibly();
|
||||
this.eventLoopGroup = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCustomTransportConfiguration(MongoClientSettings settings) {
|
||||
return settings != null && settings.getTransportSettings() != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
|
||||
import org.springframework.boot.mongodb.autoconfigure.MongoProperties.Ssl;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adapts {@link MongoProperties} to {@link MongoConnectionDetails}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class PropertiesMongoConnectionDetails implements MongoConnectionDetails {
|
||||
|
||||
private final MongoProperties properties;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
public PropertiesMongoConnectionDetails(MongoProperties properties, SslBundles sslBundles) {
|
||||
this.properties = properties;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionString getConnectionString() {
|
||||
// protocol://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database.collection][?options]]
|
||||
if (this.properties.getUri() != null) {
|
||||
return new ConnectionString(this.properties.getUri());
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(getProtocol()).append("://");
|
||||
if (this.properties.getUsername() != null) {
|
||||
builder.append(encode(this.properties.getUsername()));
|
||||
builder.append(":");
|
||||
if (this.properties.getPassword() != null) {
|
||||
builder.append(encode(this.properties.getPassword()));
|
||||
}
|
||||
builder.append("@");
|
||||
}
|
||||
builder.append((this.properties.getHost() != null) ? this.properties.getHost() : "localhost");
|
||||
if (this.properties.getPort() != null) {
|
||||
builder.append(":");
|
||||
builder.append(this.properties.getPort());
|
||||
}
|
||||
if (this.properties.getAdditionalHosts() != null) {
|
||||
builder.append(",");
|
||||
builder.append(String.join(",", this.properties.getAdditionalHosts()));
|
||||
}
|
||||
builder.append("/");
|
||||
builder.append(this.properties.getMongoClientDatabase());
|
||||
List<String> options = getOptions();
|
||||
if (!options.isEmpty()) {
|
||||
builder.append("?");
|
||||
builder.append(String.join("&", options));
|
||||
}
|
||||
return new ConnectionString(builder.toString());
|
||||
}
|
||||
|
||||
private String getProtocol() {
|
||||
String protocol = this.properties.getProtocol();
|
||||
if (StringUtils.hasText(protocol)) {
|
||||
return protocol;
|
||||
}
|
||||
return "mongodb";
|
||||
}
|
||||
|
||||
private String encode(String input) {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private char[] encode(char[] input) {
|
||||
return URLEncoder.encode(new String(input), StandardCharsets.UTF_8).toCharArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridFs getGridFs() {
|
||||
return GridFs.of(PropertiesMongoConnectionDetails.this.properties.getGridfs().getDatabase(),
|
||||
PropertiesMongoConnectionDetails.this.properties.getGridfs().getBucket());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
Ssl ssl = this.properties.getSsl();
|
||||
if (!ssl.isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.hasLength(ssl.getBundle())) {
|
||||
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
|
||||
return this.sslBundles.getBundle(ssl.getBundle());
|
||||
}
|
||||
return SslBundle.systemDefault();
|
||||
}
|
||||
|
||||
private List<String> getOptions() {
|
||||
List<String> options = new ArrayList<>();
|
||||
if (StringUtils.hasText(this.properties.getReplicaSetName())) {
|
||||
options.add("replicaSet=" + this.properties.getReplicaSetName());
|
||||
}
|
||||
if (this.properties.getUsername() != null && this.properties.getAuthenticationDatabase() != null) {
|
||||
options.add("authSource=" + this.properties.getAuthenticationDatabase());
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import com.mongodb.reactivestreams.client.MongoClients;
|
||||
|
||||
/**
|
||||
* A factory for a reactive {@link MongoClient}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class ReactiveMongoClientFactory extends MongoClientFactorySupport<MongoClient> {
|
||||
|
||||
/**
|
||||
* Construct a factory for creating a {@link MongoClient}.
|
||||
* @param builderCustomizers a list of configuration settings customizers
|
||||
*/
|
||||
public ReactiveMongoClientFactory(List<MongoClientSettingsBuilderCustomizer> builderCustomizers) {
|
||||
super(builderCustomizers, MongoClients::create);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.connection.SslSettings;
|
||||
import org.bson.UuidRepresentation;
|
||||
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link MongoClientSettingsBuilderCustomizer} that applies standard settings to a
|
||||
* {@link MongoClientSettings}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class StandardMongoClientSettingsBuilderCustomizer implements MongoClientSettingsBuilderCustomizer, Ordered {
|
||||
|
||||
private final ConnectionString connectionString;
|
||||
|
||||
private final UuidRepresentation uuidRepresentation;
|
||||
|
||||
private final MongoConnectionDetails connectionDetails;
|
||||
|
||||
private final MongoProperties.Ssl ssl;
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
private int order = 0;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
* @param connectionString the connection string
|
||||
* @param uuidRepresentation the uuid representation
|
||||
* @param ssl the ssl properties
|
||||
* @param sslBundles the ssl bundles
|
||||
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of
|
||||
* {@link #StandardMongoClientSettingsBuilderCustomizer(MongoConnectionDetails, UuidRepresentation)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "3.5.0")
|
||||
public StandardMongoClientSettingsBuilderCustomizer(ConnectionString connectionString,
|
||||
UuidRepresentation uuidRepresentation, MongoProperties.Ssl ssl, SslBundles sslBundles) {
|
||||
this.connectionDetails = null;
|
||||
this.connectionString = connectionString;
|
||||
this.uuidRepresentation = uuidRepresentation;
|
||||
this.ssl = ssl;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
public StandardMongoClientSettingsBuilderCustomizer(MongoConnectionDetails connectionDetails,
|
||||
UuidRepresentation uuidRepresentation) {
|
||||
this.connectionString = null;
|
||||
this.ssl = null;
|
||||
this.sslBundles = null;
|
||||
this.connectionDetails = connectionDetails;
|
||||
this.uuidRepresentation = uuidRepresentation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(MongoClientSettings.Builder settingsBuilder) {
|
||||
settingsBuilder.uuidRepresentation(this.uuidRepresentation);
|
||||
if (this.connectionDetails != null) {
|
||||
settingsBuilder.applyConnectionString(this.connectionDetails.getConnectionString());
|
||||
settingsBuilder.applyToSslSettings(this::configureSslIfNeeded);
|
||||
}
|
||||
else {
|
||||
settingsBuilder.uuidRepresentation(this.uuidRepresentation);
|
||||
settingsBuilder.applyConnectionString(this.connectionString);
|
||||
if (this.ssl.isEnabled()) {
|
||||
settingsBuilder.applyToSslSettings(this::configureSsl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSsl(SslSettings.Builder settings) {
|
||||
settings.enabled(true);
|
||||
if (this.ssl.getBundle() != null) {
|
||||
SslBundle sslBundle = this.sslBundles.getBundle(this.ssl.getBundle());
|
||||
Assert.state(!sslBundle.getOptions().isSpecified(), "SSL options cannot be specified with MongoDB");
|
||||
settings.context(sslBundle.createSslContext());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslIfNeeded(SslSettings.Builder settings) {
|
||||
SslBundle sslBundle = this.connectionDetails.getSslBundle();
|
||||
if (sslBundle != null) {
|
||||
settings.enabled(true);
|
||||
Assert.state(!sslBundle.getOptions().isSpecified(), "SSL options cannot be specified with MongoDB");
|
||||
settings.context(sslBundle.createSslContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order value of this object.
|
||||
* @param order the new order value
|
||||
* @see #getOrder()
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for MongoDB.
|
||||
*/
|
||||
package org.springframework.boot.mongodb.autoconfigure;
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"groups": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.data.mongodb.grid-fs-database",
|
||||
"type": "java.lang.String",
|
||||
"deprecation": {
|
||||
"replacement": "spring.data.mongodb.gridfs.database",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.data.mongodb.repositories.type",
|
||||
"type": "org.springframework.boot.autoconfigure.data.RepositoryType",
|
||||
"description": "Type of Mongo repositories to enable.",
|
||||
"defaultValue": "auto"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.mongodb.uri",
|
||||
"defaultValue": "mongodb://localhost/test"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration
|
||||
org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import com.mongodb.client.internal.MongoClientImpl;
|
||||
import com.mongodb.connection.ClusterConnectionMode;
|
||||
import com.mongodb.connection.SslSettings;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoAutoConfiguration}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class MongoAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, SslAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void clientExists() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsAdded() {
|
||||
this.contextRunner.withUserConfiguration(SettingsConfig.class)
|
||||
.run((context) -> assertThat(
|
||||
getSettings(context).getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(300));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsAddedButNoHost() {
|
||||
this.contextRunner.withUserConfiguration(SettingsConfig.class)
|
||||
.run((context) -> assertThat(
|
||||
getSettings(context).getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(300));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsSslConfig() {
|
||||
this.contextRunner.withUserConfiguration(SslSettingsConfig.class)
|
||||
.run((context) -> assertThat(getSettings(context).getSslSettings().isEnabled()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresSslWhenEnabled() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.ssl.enabled=true").run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isTrue();
|
||||
assertThat(sslSettings.getContext()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("test.jks")
|
||||
void configuresSslWithBundle() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.ssl.bundle=test-bundle",
|
||||
"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks",
|
||||
"spring.ssl.bundle.jks.test-bundle.keystore.password=secret",
|
||||
"spring.ssl.bundle.jks.test-bundle.key.password=password")
|
||||
.run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isTrue();
|
||||
assertThat(sslSettings.getContext()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresProtocol() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.protocol=mongodb+srv").run((context) -> {
|
||||
MongoClientSettings settings = getSettings(context);
|
||||
assertThat(settings.getClusterSettings().getMode()).isEqualTo(ClusterConnectionMode.MULTIPLE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultProtocol() {
|
||||
this.contextRunner.run((context) -> {
|
||||
MongoClientSettings settings = getSettings(context);
|
||||
assertThat(settings.getClusterSettings().getMode()).isEqualTo(ClusterConnectionMode.SINGLE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresWithoutSslWhenDisabledWithBundle() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.ssl.enabled=false", "spring.data.mongodb.ssl.bundle=test-bundle")
|
||||
.run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotConfigureCredentialsWithoutUsername() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.authentication-database=authdb")
|
||||
.run((context) -> assertThat(getSettings(context).getCredential()).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithDefaultDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("test");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.database=mydb")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("mydb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithAuthDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.database=mydb", "spring.data.mongodb.authentication-database=authdb")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("authdb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithSpecialCharacters() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=us:er", "spring.data.mongodb.password=sec@ret")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("us:er");
|
||||
assertThat(credential.getPassword()).isEqualTo("sec@ret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("test");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotConfigureCredentialsWithoutUsernameInUri() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://localhost/mydb?authSource=authdb")
|
||||
.run((context) -> assertThat(getSettings(context).getCredential()).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithDefaultDatabase() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("admin");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb",
|
||||
"spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("mydb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithAuthDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb",
|
||||
"spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("authdb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresSingleClient() {
|
||||
this.contextRunner.withUserConfiguration(FallbackMongoClientConfig.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizerOverridesAutoConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test?appname=auto-config")
|
||||
.withUserConfiguration(SimpleCustomizerConfig.class)
|
||||
.run((context) -> assertThat(getSettings(context).getApplicationName()).isEqualTo("overridden-name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void definesPropertiesBasedConnectionDetailsByDefault() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesMongoConnectionDetails.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustomConnectionDetailsWhenDefined() {
|
||||
this.contextRunner.withBean(MongoConnectionDetails.class, () -> new MongoConnectionDetails() {
|
||||
|
||||
@Override
|
||||
public ConnectionString getConnectionString() {
|
||||
return new ConnectionString("mongodb://localhost");
|
||||
}
|
||||
|
||||
})
|
||||
.run((context) -> assertThat(context).hasSingleBean(MongoConnectionDetails.class)
|
||||
.doesNotHaveBean(PropertiesMongoConnectionDetails.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void uuidRepresentationDefaultsAreAligned() {
|
||||
this.contextRunner.run((context) -> assertThat(getSettings(context).getUuidRepresentation())
|
||||
.isEqualTo(new MongoProperties().getUuidRepresentation()));
|
||||
}
|
||||
|
||||
private MongoClientSettings getSettings(AssertableApplicationContext context) {
|
||||
assertThat(context).hasSingleBean(MongoClient.class);
|
||||
MongoClientImpl client = (MongoClientImpl) context.getBean(MongoClient.class);
|
||||
return client.getSettings();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SettingsConfig {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings() {
|
||||
return MongoClientSettings.builder()
|
||||
.applyToSocketSettings((socketSettings) -> socketSettings.connectTimeout(300, TimeUnit.MILLISECONDS))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SslSettingsConfig {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings() {
|
||||
return MongoClientSettings.builder().applyToSslSettings((ssl) -> ssl.enabled(true)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class FallbackMongoClientConfig {
|
||||
|
||||
@Bean
|
||||
MongoClient fallbackMongoClient() {
|
||||
return MongoClients.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SimpleCustomizerConfig {
|
||||
|
||||
@Bean
|
||||
MongoClientSettingsBuilderCustomizer customizer() {
|
||||
return (clientSettingsBuilder) -> clientSettingsBuilder.applicationName("overridden-name");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoClientFactorySupport}.
|
||||
*
|
||||
* @param <T> the mongo client type
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Mark Paluch
|
||||
* @author Artsiom Yudovin
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
abstract class MongoClientFactorySupportTests<T> {
|
||||
|
||||
@Test
|
||||
void canBindCharArrayPassword() {
|
||||
// gh-1572
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
TestPropertyValues.of("spring.data.mongodb.password:word").applyTo(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
MongoProperties properties = context.getBean(MongoProperties.class);
|
||||
assertThat(properties.getPassword()).isEqualTo("word".toCharArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
void allMongoClientSettingsCanBeSet() {
|
||||
MongoClientSettings.Builder builder = MongoClientSettings.builder();
|
||||
builder.applyToSocketSettings((settings) -> {
|
||||
settings.connectTimeout(1000, TimeUnit.MILLISECONDS);
|
||||
settings.readTimeout(1000, TimeUnit.MILLISECONDS);
|
||||
}).applyToServerSettings((settings) -> {
|
||||
settings.heartbeatFrequency(10001, TimeUnit.MILLISECONDS);
|
||||
settings.minHeartbeatFrequency(501, TimeUnit.MILLISECONDS);
|
||||
}).applyToConnectionPoolSettings((settings) -> {
|
||||
settings.maxWaitTime(120001, TimeUnit.MILLISECONDS);
|
||||
settings.maxConnectionLifeTime(60000, TimeUnit.MILLISECONDS);
|
||||
settings.maxConnectionIdleTime(60000, TimeUnit.MILLISECONDS);
|
||||
}).applyToSslSettings((settings) -> settings.enabled(true)).applicationName("test");
|
||||
|
||||
MongoClientSettings settings = builder.build();
|
||||
T client = createMongoClient(settings);
|
||||
MongoClientSettings wrapped = getClientSettings(client);
|
||||
assertThat(wrapped.getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getSocketSettings().getReadTimeout(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getSocketSettings().getReadTimeout(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getServerSettings().getHeartbeatFrequency(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getServerSettings().getHeartbeatFrequency(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getServerSettings().getMinHeartbeatFrequency(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getServerSettings().getMinHeartbeatFrequency(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getApplicationName()).isEqualTo(settings.getApplicationName());
|
||||
assertThat(wrapped.getConnectionPoolSettings().getMaxWaitTime(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getConnectionPoolSettings().getMaxWaitTime(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getConnectionPoolSettings().getMaxConnectionLifeTime(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getConnectionPoolSettings().getMaxConnectionLifeTime(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getConnectionPoolSettings().getMaxConnectionIdleTime(TimeUnit.MILLISECONDS))
|
||||
.isEqualTo(settings.getConnectionPoolSettings().getMaxConnectionIdleTime(TimeUnit.MILLISECONDS));
|
||||
assertThat(wrapped.getSslSettings().isEnabled()).isEqualTo(settings.getSslSettings().isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizerIsInvoked() {
|
||||
MongoClientSettingsBuilderCustomizer customizer = mock(MongoClientSettingsBuilderCustomizer.class);
|
||||
createMongoClient(customizer);
|
||||
then(customizer).should().customize(any(MongoClientSettings.Builder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void canBindAutoIndexCreation() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
TestPropertyValues.of("spring.data.mongodb.autoIndexCreation:true").applyTo(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
MongoProperties properties = context.getBean(MongoProperties.class);
|
||||
assertThat(properties.isAutoIndexCreation()).isTrue();
|
||||
}
|
||||
|
||||
protected T createMongoClient(MongoClientSettings settings) {
|
||||
return createMongoClient(null, settings);
|
||||
}
|
||||
|
||||
protected void createMongoClient(MongoClientSettingsBuilderCustomizer... customizers) {
|
||||
createMongoClient((customizers != null) ? Arrays.asList(customizers) : null,
|
||||
MongoClientSettings.builder().build());
|
||||
}
|
||||
|
||||
protected abstract T createMongoClient(List<MongoClientSettingsBuilderCustomizer> customizers,
|
||||
MongoClientSettings settings);
|
||||
|
||||
protected abstract MongoClientSettings getClientSettings(T client);
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(MongoProperties.class)
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.internal.MongoClientImpl;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoClientFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Mark Paluch
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class MongoClientFactoryTests extends MongoClientFactorySupportTests<MongoClient> {
|
||||
|
||||
@Override
|
||||
protected MongoClient createMongoClient(List<MongoClientSettingsBuilderCustomizer> customizers,
|
||||
MongoClientSettings settings) {
|
||||
return new MongoClientFactory(customizers).createMongoClient(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoClientSettings getClientSettings(MongoClient client) {
|
||||
return ((MongoClientImpl) client).getSettings();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.connection.NettyTransportSettings;
|
||||
import com.mongodb.connection.SslSettings;
|
||||
import com.mongodb.connection.TransportSettings;
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import com.mongodb.reactivestreams.client.internal.MongoClientImpl;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoReactiveAutoConfiguration}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class MongoReactiveAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(MongoReactiveAutoConfiguration.class, SslAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void clientExists() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsAdded() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.host:localhost")
|
||||
.withUserConfiguration(SettingsConfig.class)
|
||||
.run((context) -> assertThat(getSettings(context).getSocketSettings().getReadTimeout(TimeUnit.SECONDS))
|
||||
.isEqualTo(300));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsAddedButNoHost() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test")
|
||||
.withUserConfiguration(SettingsConfig.class)
|
||||
.run((context) -> assertThat(getSettings(context).getReadPreference()).isEqualTo(ReadPreference.nearest()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void settingsSslConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test")
|
||||
.withUserConfiguration(SslSettingsConfig.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(MongoClient.class);
|
||||
MongoClientSettings settings = getSettings(context);
|
||||
assertThat(settings.getApplicationName()).isEqualTo("test-config");
|
||||
assertThat(settings.getTransportSettings()).isSameAs(context.getBean("myTransportSettings"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresSslWhenEnabled() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.ssl.enabled=true").run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isTrue();
|
||||
assertThat(sslSettings.getContext()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("test.jks")
|
||||
void configuresSslWithBundle() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.ssl.bundle=test-bundle",
|
||||
"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks",
|
||||
"spring.ssl.bundle.jks.test-bundle.keystore.password=secret",
|
||||
"spring.ssl.bundle.jks.test-bundle.key.password=password")
|
||||
.run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isTrue();
|
||||
assertThat(sslSettings.getContext()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresWithoutSslWhenDisabledWithBundle() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.ssl.enabled=false", "spring.data.mongodb.ssl.bundle=test-bundle")
|
||||
.run((context) -> {
|
||||
SslSettings sslSettings = getSettings(context).getSslSettings();
|
||||
assertThat(sslSettings.isEnabled()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotConfigureCredentialsWithoutUsername() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.authentication-database=authdb")
|
||||
.run((context) -> assertThat(getSettings(context).getCredential()).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithDefaultDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("test");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.database=mydb")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("mydb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromPropertiesWithAuthDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret",
|
||||
"spring.data.mongodb.database=mydb", "spring.data.mongodb.authentication-database=authdb")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("authdb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotConfigureCredentialsWithoutUsernameInUri() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://localhost/mydb?authSource=authdb")
|
||||
.run((context) -> assertThat(getSettings(context).getCredential()).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithDefaultDatabase() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("admin");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb",
|
||||
"spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("mydb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configuresCredentialsFromUriPropertyWithAuthDatabase() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb",
|
||||
"spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused")
|
||||
.run((context) -> {
|
||||
MongoCredential credential = getSettings(context).getCredential();
|
||||
assertThat(credential.getUserName()).isEqualTo("user");
|
||||
assertThat(credential.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(credential.getSource()).isEqualTo("authdb");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void nettyTransportSettingsAreConfiguredAutomatically() {
|
||||
AtomicReference<EventLoopGroup> eventLoopGroupReference = new AtomicReference<>();
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(MongoClient.class);
|
||||
TransportSettings transportSettings = getSettings(context).getTransportSettings();
|
||||
assertThat(transportSettings).isInstanceOf(NettyTransportSettings.class);
|
||||
EventLoopGroup eventLoopGroup = ((NettyTransportSettings) transportSettings).getEventLoopGroup();
|
||||
assertThat(eventLoopGroup.isShutdown()).isFalse();
|
||||
eventLoopGroupReference.set(eventLoopGroup);
|
||||
});
|
||||
assertThat(eventLoopGroupReference.get().isShutdown()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void customizerWithTransportSettingsOverridesAutoConfig() {
|
||||
this.contextRunner.withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test?appname=auto-config")
|
||||
.withUserConfiguration(SimpleTransportSettingsCustomizerConfig.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(MongoClient.class);
|
||||
MongoClientSettings settings = getSettings(context);
|
||||
assertThat(settings.getApplicationName()).isEqualTo("custom-transport-settings");
|
||||
assertThat(settings.getTransportSettings())
|
||||
.isSameAs(SimpleTransportSettingsCustomizerConfig.transportSettings);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void definesPropertiesBasedConnectionDetailsByDefault() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesMongoConnectionDetails.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustomConnectionDetailsWhenDefined() {
|
||||
this.contextRunner.withBean(MongoConnectionDetails.class, () -> new MongoConnectionDetails() {
|
||||
|
||||
@Override
|
||||
public ConnectionString getConnectionString() {
|
||||
return new ConnectionString("mongodb://localhost");
|
||||
}
|
||||
|
||||
})
|
||||
.run((context) -> assertThat(context).hasSingleBean(MongoConnectionDetails.class)
|
||||
.doesNotHaveBean(PropertiesMongoConnectionDetails.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void uuidRepresentationDefaultsAreAligned() {
|
||||
this.contextRunner.run((context) -> assertThat(getSettings(context).getUuidRepresentation())
|
||||
.isEqualTo(new MongoProperties().getUuidRepresentation()));
|
||||
}
|
||||
|
||||
private MongoClientSettings getSettings(ApplicationContext context) {
|
||||
MongoClientImpl client = (MongoClientImpl) context.getBean(MongoClient.class);
|
||||
return client.getSettings();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SettingsConfig {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings() {
|
||||
return MongoClientSettings.builder()
|
||||
.readPreference(ReadPreference.nearest())
|
||||
.applyToSocketSettings((socket) -> socket.readTimeout(300, TimeUnit.SECONDS))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SslSettingsConfig {
|
||||
|
||||
@Bean
|
||||
MongoClientSettings mongoClientSettings(TransportSettings transportSettings) {
|
||||
return MongoClientSettings.builder()
|
||||
.applicationName("test-config")
|
||||
.transportSettings(transportSettings)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TransportSettings myTransportSettings() {
|
||||
return TransportSettings.nettyBuilder().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SimpleTransportSettingsCustomizerConfig {
|
||||
|
||||
private static final TransportSettings transportSettings = TransportSettings.nettyBuilder().build();
|
||||
|
||||
@Bean
|
||||
MongoClientSettingsBuilderCustomizer customizer() {
|
||||
return (clientSettingsBuilder) -> clientSettingsBuilder.applicationName("custom-transport-settings")
|
||||
.transportSettings(transportSettings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2012-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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.ConnectionString;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.ssl.DefaultSslBundleRegistry;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertiesMongoConnectionDetails}.
|
||||
*
|
||||
* @author Christoph Dreis
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class PropertiesMongoConnectionDetailsTests {
|
||||
|
||||
private MongoProperties properties;
|
||||
|
||||
private DefaultSslBundleRegistry sslBundleRegistry;
|
||||
|
||||
private PropertiesMongoConnectionDetails connectionDetails;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.properties = new MongoProperties();
|
||||
this.sslBundleRegistry = new DefaultSslBundleRegistry();
|
||||
this.connectionDetails = new PropertiesMongoConnectionDetails(this.properties, this.sslBundleRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsCanBeConfiguredWithUsername() {
|
||||
this.properties.setUsername("user");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getUsername()).isEqualTo("user");
|
||||
assertThat(connectionString.getPassword()).isEmpty();
|
||||
assertThat(connectionString.getCredential().getUserName()).isEqualTo("user");
|
||||
assertThat(connectionString.getCredential().getPassword()).isEmpty();
|
||||
assertThat(connectionString.getCredential().getSource()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsCanBeConfiguredWithUsernameAndPassword() {
|
||||
this.properties.setUsername("user");
|
||||
this.properties.setPassword("secret".toCharArray());
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getUsername()).isEqualTo("user");
|
||||
assertThat(connectionString.getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(connectionString.getCredential().getUserName()).isEqualTo("user");
|
||||
assertThat(connectionString.getCredential().getPassword()).isEqualTo("secret".toCharArray());
|
||||
assertThat(connectionString.getCredential().getSource()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void databaseCanBeConfigured() {
|
||||
this.properties.setDatabase("db");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getDatabase()).isEqualTo("db");
|
||||
}
|
||||
|
||||
@Test
|
||||
void databaseHasDefaultWhenNotConfigured() {
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getDatabase()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void protocolCanBeConfigured() {
|
||||
this.properties.setProtocol("mongodb+srv");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getConnectionString()).startsWith("mongodb+srv://");
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationDatabaseCanBeConfigured() {
|
||||
this.properties.setUsername("user");
|
||||
this.properties.setDatabase("db");
|
||||
this.properties.setAuthenticationDatabase("authdb");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getDatabase()).isEqualTo("db");
|
||||
assertThat(connectionString.getCredential().getSource()).isEqualTo("authdb");
|
||||
assertThat(connectionString.getCredential().getUserName()).isEqualTo("user");
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticationDatabaseIsNotConfiguredWhenUsernameIsNotConfigured() {
|
||||
this.properties.setAuthenticationDatabase("authdb");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getCredential()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replicaSetCanBeConfigured() {
|
||||
this.properties.setReplicaSetName("test");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getRequiredReplicaSetName()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void replicaSetCanBeConfiguredWithDatabase() {
|
||||
this.properties.setUsername("user");
|
||||
this.properties.setDatabase("db");
|
||||
this.properties.setReplicaSetName("test");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getDatabase()).isEqualTo("db");
|
||||
assertThat(connectionString.getRequiredReplicaSetName()).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void replicaSetCanBeNull() {
|
||||
this.properties.setReplicaSetName(null);
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getRequiredReplicaSetName()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replicaSetCanBeBlank() {
|
||||
this.properties.setReplicaSetName("");
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getRequiredReplicaSetName()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAdditionalHostsAreConfiguredThenTheyAreIncludedInHostsOfConnectionString() {
|
||||
this.properties.setHost("mongo1.example.com");
|
||||
this.properties.setAdditionalHosts(List.of("mongo2.example.com", "mongo3.example.com"));
|
||||
ConnectionString connectionString = this.connectionDetails.getConnectionString();
|
||||
assertThat(connectionString.getHosts()).containsExactly("mongo1.example.com", "mongo2.example.com",
|
||||
"mongo3.example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSslBundle() {
|
||||
SslBundle bundle1 = mock(SslBundle.class);
|
||||
this.sslBundleRegistry.registerBundle("bundle-1", bundle1);
|
||||
this.properties.getSsl().setBundle("bundle-1");
|
||||
SslBundle sslBundle = this.connectionDetails.getSslBundle();
|
||||
assertThat(sslBundle).isSameAs(bundle1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSystemDefaultBundleIfSslIsEnabledButBundleNotSet() {
|
||||
this.properties.getSsl().setEnabled(true);
|
||||
SslBundle sslBundle = this.connectionDetails.getSslBundle();
|
||||
assertThat(sslBundle).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNullIfSslIsNotEnabled() {
|
||||
this.properties.getSsl().setEnabled(false);
|
||||
SslBundle sslBundle = this.connectionDetails.getSslBundle();
|
||||
assertThat(sslBundle).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.boot.mongodb.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.reactivestreams.client.MongoClient;
|
||||
import com.mongodb.reactivestreams.client.internal.MongoClientImpl;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReactiveMongoClientFactory}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class ReactiveMongoClientFactoryTests extends MongoClientFactorySupportTests<MongoClient> {
|
||||
|
||||
@Override
|
||||
protected MongoClient createMongoClient(List<MongoClientSettingsBuilderCustomizer> customizers,
|
||||
MongoClientSettings settings) {
|
||||
return new ReactiveMongoClientFactory(customizers).createMongoClient(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoClientSettings getClientSettings(MongoClient client) {
|
||||
return ((MongoClientImpl) client).getSettings();
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user