Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26a31d07f5 | ||
|
|
aa5bdcd3fa | ||
|
|
2354b66c76 | ||
|
|
5b02bf0b51 | ||
|
|
2a061b9725 | ||
|
|
4f10d0cf05 | ||
|
|
8be3f02ab8 | ||
|
|
7baeb4bd9e | ||
|
|
05ca193331 | ||
|
|
b08990ccd0 | ||
|
|
f3770a4066 | ||
|
|
38b7a72f02 | ||
|
|
bccd9e22c0 | ||
|
|
6052571ff7 | ||
|
|
8ddbc3c206 | ||
|
|
2669dcb9bf | ||
|
|
295f7de8af | ||
|
|
7d20d640e8 | ||
|
|
704c130d94 | ||
|
|
3e5b4f25a4 | ||
|
|
22d49fea86 | ||
|
|
a224943f30 | ||
|
|
9d4c79e5c3 | ||
|
|
eff10210ed | ||
|
|
f151060773 | ||
|
|
7e6fd2e62a | ||
|
|
0cc050e966 | ||
|
|
e30eeaae79 | ||
|
|
b8cb2f74cf | ||
|
|
c876155d34 | ||
|
|
4e0c8a1525 | ||
|
|
eee7389d5c | ||
|
|
9890ac2aa5 | ||
|
|
2026cd3d22 | ||
|
|
4e8fdb97cc | ||
|
|
151441f908 | ||
|
|
abe2dddb1e | ||
|
|
ed777b53e4 | ||
|
|
855c9d4fab | ||
|
|
e0b8f5b566 | ||
|
|
82850d1605 | ||
|
|
8d0601550c | ||
|
|
282b63f7c2 | ||
|
|
0cb869ba97 | ||
|
|
c4fc32624b | ||
|
|
144000ed46 | ||
|
|
9f10921a48 | ||
|
|
c2127760cc | ||
|
|
d2f90bae5d | ||
|
|
b25fde4ff3 | ||
|
|
e23ca446a2 | ||
|
|
4c3b1951e2 | ||
|
|
3474f7e037 | ||
|
|
5308b8f446 | ||
|
|
e267f329fb | ||
|
|
234009cf53 | ||
|
|
ab4fb8477d | ||
|
|
76bec5e42d | ||
|
|
42beaaf47e | ||
|
|
f32afed779 | ||
|
|
b442abeef9 | ||
|
|
377c421052 | ||
|
|
fdef631c6e | ||
|
|
7ec61c9360 | ||
|
|
a95b9577da | ||
|
|
a02fe28644 | ||
|
|
d620546a3e | ||
|
|
f1621364b0 | ||
|
|
02578a0168 | ||
|
|
4bab7b32f2 | ||
|
|
0bda096e61 | ||
|
|
17139dcf3b | ||
|
|
bebfea0d33 | ||
|
|
885f0f4b70 | ||
|
|
a6000ee771 | ||
|
|
d4792cd680 | ||
|
|
949833a7db | ||
|
|
5abf1147e4 | ||
|
|
d65be17338 | ||
|
|
d1f915f702 | ||
|
|
58d50aa1ff | ||
|
|
0f30ffa090 | ||
|
|
496331d755 | ||
|
|
7658e1f1d3 | ||
|
|
221e03947b | ||
|
|
f0aed498d5 | ||
|
|
a62f6b8043 | ||
|
|
3f16b30631 | ||
|
|
8ebcbe3c5c | ||
|
|
363bed5c37 | ||
|
|
1547a646dd | ||
|
|
1408d51065 | ||
|
|
f5c319f18f | ||
|
|
a3c29054d0 | ||
|
|
01533ca34c | ||
|
|
a1f6dc6db4 | ||
|
|
37d53d936d | ||
|
|
bc0a2df653 | ||
|
|
7e50fd8273 | ||
|
|
ba560ffbad | ||
|
|
50ca32c8b9 | ||
|
|
bdfe3af505 | ||
|
|
798b56055d | ||
|
|
ce68e4a070 | ||
|
|
5da3130d26 | ||
|
|
6687cdc101 | ||
|
|
7e74ec6b62 | ||
|
|
b887fa70a5 | ||
|
|
1c6ab25253 | ||
|
|
1c43a3d1ee | ||
|
|
60ca1b3509 | ||
|
|
39d9312005 | ||
|
|
a0e42f5dfe | ||
|
|
7a3aff12a5 | ||
|
|
d4f1ef8704 | ||
|
|
a86d704bec | ||
|
|
57ab27aa5b | ||
|
|
909cc8b5d3 | ||
|
|
b7acbc4347 | ||
|
|
d276306ddc | ||
|
|
25b98b7ad2 | ||
|
|
819b424142 | ||
|
|
5d0328ba4b | ||
|
|
b219cff29c | ||
|
|
409eeaf962 | ||
|
|
4e5e8bd026 | ||
|
|
b91ec53ae0 | ||
|
|
ce0624b8b0 | ||
|
|
b4de2769cf | ||
|
|
3f7b0f1eb6 | ||
|
|
4055365c57 | ||
|
|
db7f782ca6 | ||
|
|
cde9d8d23a | ||
|
|
3dd9b0a2b6 | ||
|
|
59e54cecd2 | ||
|
|
5ed7e8efc2 | ||
|
|
fa85adfe0b | ||
|
|
a3e4f44a64 | ||
|
|
4a7a485e62 | ||
|
|
c353e02b3e | ||
|
|
1c2964cab4 | ||
|
|
47e083280a | ||
|
|
7db003100b | ||
|
|
f814b1ef47 | ||
|
|
f3d2ae366e | ||
|
|
b6ecce3aa2 | ||
|
|
c5235be9a7 | ||
|
|
23300de9d4 |
22
.travis.yml
Normal file
22
.travis.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
language: java
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
services:
|
||||
- mongodb
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- PROFILE=ci
|
||||
- PROFILE=mongo-next
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
|
||||
install: true
|
||||
|
||||
script: "mvn clean dependency:list test -P${PROFILE} -Dsort"
|
||||
32
pom.xml
32
pom.xml
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,8 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.6.0.M1</version>
|
||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||
<version>1.6.3.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -29,9 +28,9 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>1.10.0.M1</springdata.commons>
|
||||
<mongo>2.12.3</mongo>
|
||||
<mongo.osgi>2.12.3</mongo.osgi>
|
||||
<springdata.commons>1.10.3.BUILD-SNAPSHOT</springdata.commons>
|
||||
<mongo>2.13.0</mongo>
|
||||
<mongo.osgi>2.13.0</mongo.osgi>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
@@ -108,7 +107,7 @@
|
||||
|
||||
<id>mongo-next</id>
|
||||
<properties>
|
||||
<mongo>2.12.5-SNAPSHOT</mongo>
|
||||
<mongo>2.14.0-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -122,7 +121,16 @@
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo-3-next</id>
|
||||
<id>mongo3</id>
|
||||
<properties>
|
||||
<mongo>3.0.2</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo3-next</id>
|
||||
<properties>
|
||||
<mongo>3.0.0-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
@@ -148,15 +156,15 @@
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-milestone</id>
|
||||
<url>http://repo.spring.io/libs-milestone</url>
|
||||
<id>spring-libs-snapshot</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>http://repo.spring.io/plugins-release</url>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<name>Spring Data MongoDB - Cross-Store Support</name>
|
||||
|
||||
<properties>
|
||||
<jpa>1.0.0.Final</jpa>
|
||||
<jpa>2.0.0</jpa>
|
||||
<hibernate>3.6.10.Final</hibernate>
|
||||
</properties>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -59,8 +59,8 @@
|
||||
|
||||
<!-- JPA -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>javax.persistence</artifactId>
|
||||
<version>${jpa}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,6 +37,8 @@ import com.mongodb.MongoException;
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Oliver Gierke
|
||||
* @author Alex Vengrovsk
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
|
||||
@@ -45,7 +47,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
private static final String ENTITY_FIELD_NAME = "_entity_field_name";
|
||||
private static final String ENTITY_FIELD_CLASS = "_entity_field_class";
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private MongoTemplate mongoTemplate;
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
@@ -76,25 +78,25 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
dbk.put(ENTITY_ID, id);
|
||||
dbk.put(ENTITY_CLASS, entityClass.getName());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Loading MongoDB data for " + dbk);
|
||||
log.debug("Loading MongoDB data for {}", dbk);
|
||||
}
|
||||
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
for (DBObject dbo : collection.find(dbk)) {
|
||||
String key = (String) dbo.get(ENTITY_FIELD_NAME);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Processing key: " + key);
|
||||
log.debug("Processing key: {}", key);
|
||||
}
|
||||
if (!changeSet.getValues().containsKey(key)) {
|
||||
String className = (String) dbo.get(ENTITY_FIELD_CLASS);
|
||||
if (className == null) {
|
||||
throw new DataIntegrityViolationException("Unble to convert property " + key + ": Invalid metadata, "
|
||||
+ ENTITY_FIELD_CLASS + " not available");
|
||||
throw new DataIntegrityViolationException(
|
||||
"Unble to convert property " + key + ": Invalid metadata, " + ENTITY_FIELD_CLASS + " not available");
|
||||
}
|
||||
Class<?> clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
|
||||
Object value = mongoTemplate.getConverter().read(clazz, dbo);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding to ChangeSet: " + key);
|
||||
log.debug("Adding to ChangeSet: {}", key);
|
||||
}
|
||||
changeSet.set(key, value);
|
||||
}
|
||||
@@ -109,9 +111,9 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||
*/
|
||||
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||
|
||||
log.debug("getPersistentId called on " + entity);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("getPersistentId called on {}", entity);
|
||||
}
|
||||
if (entityManagerFactory == null) {
|
||||
throw new DataAccessResourceFailureException("EntityManagerFactory cannot be null");
|
||||
}
|
||||
@@ -130,7 +132,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Flush: changeset: " + cs.getValues());
|
||||
log.debug("Flush: changeset: {}", cs.getValues());
|
||||
}
|
||||
|
||||
String collName = getCollectionNameForEntity(entity.getClass());
|
||||
@@ -152,7 +154,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
});
|
||||
if (value == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Flush: removing: " + dbQuery);
|
||||
log.debug("Flush: removing: {}", dbQuery);
|
||||
}
|
||||
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
@@ -164,7 +166,7 @@ public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||
final DBObject dbDoc = new BasicDBObject();
|
||||
dbDoc.putAll(dbQuery);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Flush: saving: " + dbQuery);
|
||||
log.debug("Flush: saving: {}", dbQuery);
|
||||
}
|
||||
mongoTemplate.getConverter().write(value, dbDoc);
|
||||
dbDoc.put(ENTITY_FIELD_CLASS, value.getClass().getName());
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
|
||||
// Copy properties into document
|
||||
Map<Object, Object> props = event.getProperties();
|
||||
if (null != props && props.size() > 0) {
|
||||
if (null != props && !props.isEmpty()) {
|
||||
BasicDBObject propsDbo = new BasicDBObject();
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
propsDbo.put(entry.getKey().toString(), entry.getValue().toString());
|
||||
|
||||
@@ -39,7 +39,7 @@ public class MongoLog4jAppenderIntegrationTests {
|
||||
|
||||
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
|
||||
|
||||
Logger log = Logger.getLogger(NAME);
|
||||
private static final Logger log = Logger.getLogger(NAME);
|
||||
Mongo mongo;
|
||||
DB db;
|
||||
String collection;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.7.3.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -138,6 +138,20 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.threeten</groupId>
|
||||
<artifactId>threetenbp</artifactId>
|
||||
<version>${threetenbp}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jul-to-slf4j</artifactId>
|
||||
@@ -151,6 +165,13 @@
|
||||
<version>${equalsverifier}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -46,6 +46,7 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Base class for Spring Data MongoDB configuration using JavaConfig.
|
||||
@@ -54,6 +55,7 @@ import com.mongodb.Mongo;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Ryan Tenney
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractMongoConfiguration {
|
||||
@@ -70,7 +72,10 @@ public abstract class AbstractMongoConfiguration {
|
||||
* returned by {@link #getDatabaseName()} later on effectively.
|
||||
*
|
||||
* @return
|
||||
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||
* {@link MongoClient#getCredentialsList()}
|
||||
*/
|
||||
@Deprecated
|
||||
protected String getAuthenticationDatabaseName() {
|
||||
return null;
|
||||
}
|
||||
@@ -129,7 +134,10 @@ public abstract class AbstractMongoConfiguration {
|
||||
* be used.
|
||||
*
|
||||
* @return
|
||||
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||
* {@link MongoClient#getCredentialsList()}
|
||||
*/
|
||||
@Deprecated
|
||||
protected UserCredentials getUserCredentials() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for {@code mongo-client} definitions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoClientParser implements BeanDefinitionParser {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
String id = element.getAttribute("id");
|
||||
|
||||
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoClientFactoryBean.class);
|
||||
|
||||
ParsingUtils.setPropertyValue(builder, element, "port", "port");
|
||||
ParsingUtils.setPropertyValue(builder, element, "host", "host");
|
||||
ParsingUtils.setPropertyValue(builder, element, "credentials", "credentials");
|
||||
|
||||
MongoParsingUtils.parseMongoClientOptions(element, builder);
|
||||
MongoParsingUtils.parseReplicaSet(element, builder);
|
||||
|
||||
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
||||
|
||||
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
|
||||
|
||||
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||
parserContext.registerBeanComponent(mongoComponent);
|
||||
|
||||
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||
.getServerAddressPropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||
|
||||
BeanComponentDefinition writeConcernEditor = helper.getComponent(MongoParsingUtils
|
||||
.getWriteConcernPropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(writeConcernEditor);
|
||||
|
||||
BeanComponentDefinition readPreferenceEditor = helper.getComponent(MongoParsingUtils
|
||||
.getReadPreferencePropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(readPreferenceEditor);
|
||||
|
||||
BeanComponentDefinition credentialsEditor = helper.getComponent(MongoParsingUtils
|
||||
.getMongoCredentialPropertyEditor());
|
||||
parserContext.registerBeanComponent(credentialsEditor);
|
||||
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
return mongoComponent.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.MongoCredential;
|
||||
|
||||
/**
|
||||
* Parse a {@link String} to a Collection of {@link MongoCredential}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
private static final Pattern GROUP_PATTERN = Pattern.compile("(\\\\?')(.*?)\\1");
|
||||
|
||||
private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
|
||||
private static final String USERNAME_PASSWORD_DELIMINATOR = ":";
|
||||
private static final String DATABASE_DELIMINATOR = "@";
|
||||
private static final String OPTIONS_DELIMINATOR = "?";
|
||||
private static final String OPTION_VALUE_DELIMINATOR = "&";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
|
||||
if (!StringUtils.hasText(text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<MongoCredential> credentials = new ArrayList<MongoCredential>();
|
||||
|
||||
for (String credentialString : extractCredentialsString(text)) {
|
||||
|
||||
String[] userNameAndPassword = extractUserNameAndPassword(credentialString);
|
||||
String database = extractDB(credentialString);
|
||||
Properties options = extractOptions(credentialString);
|
||||
|
||||
if (!options.isEmpty()) {
|
||||
|
||||
if (options.containsKey(AUTH_MECHANISM_KEY)) {
|
||||
|
||||
String authMechanism = options.getProperty(AUTH_MECHANISM_KEY);
|
||||
|
||||
if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {
|
||||
|
||||
verifyUserNamePresent(userNameAndPassword);
|
||||
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
|
||||
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
|
||||
|
||||
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
||||
verifyDatabasePresent(database);
|
||||
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
|
||||
userNameAndPassword[1].toCharArray()));
|
||||
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
|
||||
|
||||
verifyUserNamePresent(userNameAndPassword);
|
||||
credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
|
||||
} else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {
|
||||
|
||||
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
||||
verifyDatabasePresent(database);
|
||||
credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
|
||||
userNameAndPassword[1].toCharArray()));
|
||||
} else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {
|
||||
|
||||
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
||||
verifyDatabasePresent(database);
|
||||
credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
|
||||
userNameAndPassword[1].toCharArray()));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot create MongoCredentials for unknown auth mechanism '%s'!", authMechanism));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
||||
verifyDatabasePresent(database);
|
||||
credentials.add(
|
||||
MongoCredential.createCredential(userNameAndPassword[0], database, userNameAndPassword[1].toCharArray()));
|
||||
}
|
||||
}
|
||||
|
||||
setValue(credentials);
|
||||
}
|
||||
|
||||
private List<String> extractCredentialsString(String source) {
|
||||
|
||||
Matcher matcher = GROUP_PATTERN.matcher(source);
|
||||
List<String> list = new ArrayList<String>();
|
||||
|
||||
while (matcher.find()) {
|
||||
|
||||
String value = StringUtils.trimLeadingCharacter(matcher.group(), '\'');
|
||||
list.add(StringUtils.trimTrailingCharacter(value, '\''));
|
||||
}
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return list;
|
||||
}
|
||||
|
||||
return Arrays.asList(source.split(","));
|
||||
}
|
||||
|
||||
private static String[] extractUserNameAndPassword(String text) {
|
||||
|
||||
int index = text.lastIndexOf(DATABASE_DELIMINATOR);
|
||||
|
||||
index = index != -1 ? index : text.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||
|
||||
return index == -1 ? new String[] {} : text.substring(0, index).split(USERNAME_PASSWORD_DELIMINATOR);
|
||||
}
|
||||
|
||||
private static String extractDB(String text) {
|
||||
|
||||
int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
|
||||
|
||||
if (dbSeperationIndex == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String tmp = text.substring(dbSeperationIndex + 1);
|
||||
int optionsSeperationIndex = tmp.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||
|
||||
return optionsSeperationIndex > -1 ? tmp.substring(0, optionsSeperationIndex) : tmp;
|
||||
}
|
||||
|
||||
private static Properties extractOptions(String text) {
|
||||
|
||||
int optionsSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||
int dbSeperationIndex = text.lastIndexOf(OPTIONS_DELIMINATOR);
|
||||
|
||||
if (optionsSeperationIndex == -1 || dbSeperationIndex > optionsSeperationIndex) {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
Properties properties = new Properties();
|
||||
|
||||
for (String option : text.substring(optionsSeperationIndex + 1).split(OPTION_VALUE_DELIMINATOR)) {
|
||||
String[] optionArgs = option.split("=");
|
||||
properties.put(optionArgs[0], optionArgs[1]);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static void verifyUsernameAndPasswordPresent(String[] source) {
|
||||
|
||||
verifyUserNamePresent(source);
|
||||
|
||||
if (source.length != 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"Credentials need to specify username and password like in 'username:password@database'!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyDatabasePresent(String source) {
|
||||
|
||||
if (!StringUtils.hasText(source)) {
|
||||
throw new IllegalArgumentException("Credentials need to specify database like in 'username:password@database'!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyUserNamePresent(String[] source) {
|
||||
|
||||
if (source.length == 0 || !StringUtils.hasText(source[0])) {
|
||||
throw new IllegalArgumentException("Credentials need to specify username!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Martin Baumgartner
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
@@ -33,6 +34,7 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
||||
registerBeanDefinitionParser("mongo", new MongoParser());
|
||||
registerBeanDefinitionParser("mongo-client", new MongoClientParser());
|
||||
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
||||
registerBeanDefinitionParser("jmx", new MongoJmxParser());
|
||||
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.CustomEditorConfigurer;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
@@ -36,6 +32,7 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoParser implements BeanDefinitionParser {
|
||||
|
||||
@@ -64,7 +61,8 @@ public class MongoParser implements BeanDefinitionParser {
|
||||
|
||||
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||
parserContext.registerBeanComponent(mongoComponent);
|
||||
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(registerServerAddressPropertyEditor());
|
||||
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||
.getServerAddressPropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||
.getWriteConcernPropertyEditorBuilder());
|
||||
@@ -75,19 +73,4 @@ public class MongoParser implements BeanDefinitionParser {
|
||||
return mongoComponent.getBeanDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* One should only register one bean definition but want to have the convenience of using
|
||||
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
|
||||
* container.
|
||||
*/
|
||||
private BeanDefinitionBuilder registerServerAddressPropertyEditor() {
|
||||
|
||||
Map<String, String> customEditors = new ManagedMap<String, String>();
|
||||
customEditors.put("com.mongodb.ServerAddress[]",
|
||||
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||
builder.addPropertyValue("customEditors", customEditors);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.beans.factory.config.CustomEditorConfigurer;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.data.mongodb.core.MongoClientOptionsFactoryBean;
|
||||
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -33,13 +34,13 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
abstract class MongoParsingUtils {
|
||||
|
||||
private MongoParsingUtils() {
|
||||
|
||||
}
|
||||
private MongoParsingUtils() {}
|
||||
|
||||
/**
|
||||
* Parses the mongo replica-set element.
|
||||
@@ -54,12 +55,14 @@ abstract class MongoParsingUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
|
||||
* Parses the {@code mongo:options} sub-element. Populates the given attribute factory with the proper attributes.
|
||||
*
|
||||
* @return true if parsing actually occured, false otherwise
|
||||
* @return true if parsing actually occured, {@literal false} otherwise
|
||||
*/
|
||||
static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
|
||||
|
||||
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
|
||||
|
||||
if (optionsElement == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -80,13 +83,58 @@ abstract class MongoParsingUtils {
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||
setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||
setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||
|
||||
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the {@code mongo:client-options} sub-element. Populates the given attribute factory with the proper
|
||||
* attributes.
|
||||
*
|
||||
* @param element must not be {@literal null}.
|
||||
* @param mongoClientBuilder must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean parseMongoClientOptions(Element element, BeanDefinitionBuilder mongoClientBuilder) {
|
||||
|
||||
Element optionsElement = DomUtils.getChildElementByTagName(element, "client-options");
|
||||
|
||||
if (optionsElement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(MongoClientOptionsFactoryBean.class);
|
||||
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "description", "description");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-connections-per-host", "minConnectionsPerHost");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
|
||||
"threadsAllowedToBlockForConnectionMultiplier");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-idle-time", "maxConnectionIdleTime");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-life-time", "maxConnectionLifeTime");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "read-preference", "readPreference");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "write-concern", "writeConcern");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-frequency", "heartbeatFrequency");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-heartbeat-frequency", "minHeartbeatFrequency");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-connect-timeout", "heartbeatConnectTimeout");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||
|
||||
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
||||
* {@link WriteConcernPropertyEditor}.
|
||||
@@ -103,4 +151,56 @@ abstract class MongoParsingUtils {
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* One should only register one bean definition but want to have the convenience of using
|
||||
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
|
||||
* container.
|
||||
*/
|
||||
static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
|
||||
|
||||
Map<String, String> customEditors = new ManagedMap<String, String>();
|
||||
customEditors.put("com.mongodb.ServerAddress[]",
|
||||
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||
builder.addPropertyValue("customEditors", customEditors);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
||||
* {@link ReadPreferencePropertyEditor}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
|
||||
|
||||
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
|
||||
customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.class);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||
builder.addPropertyValue("customEditors", customEditors);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
||||
* {@link MongoCredentialPropertyEditor}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
static BeanDefinitionBuilder getMongoCredentialPropertyEditor() {
|
||||
|
||||
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
|
||||
customEditors.put("com.mongodb.MongoCredential[]", MongoCredentialPropertyEditor.class);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||
builder.addPropertyValue("customEditors", customEditors);
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import com.mongodb.ReadPreference;
|
||||
|
||||
/**
|
||||
* Parse a {@link String} to a {@link ReadPreference}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setAsText(String readPreferenceString) throws IllegalArgumentException {
|
||||
|
||||
if (readPreferenceString == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReadPreference preference = null;
|
||||
|
||||
try {
|
||||
preference = ReadPreference.valueOf(readPreferenceString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// ignore this one and try to map it differently
|
||||
}
|
||||
|
||||
if (preference != null) {
|
||||
setValue(preference);
|
||||
} else if ("PRIMARY".equalsIgnoreCase(readPreferenceString)) {
|
||||
setValue(ReadPreference.primary());
|
||||
} else if ("PRIMARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
|
||||
setValue(ReadPreference.primaryPreferred());
|
||||
} else if ("SECONDARY".equalsIgnoreCase(readPreferenceString)) {
|
||||
setValue(ReadPreference.secondary());
|
||||
} else if ("SECONDARY_PREFERRED".equalsIgnoreCase(readPreferenceString)) {
|
||||
setValue(ReadPreference.secondaryPreferred());
|
||||
} else if ("NEAREST".equalsIgnoreCase(readPreferenceString)) {
|
||||
setValue(ReadPreference.nearest());
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Cannot find matching ReadPreference for %s",
|
||||
readPreferenceString));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import com.mongodb.DBCursor;
|
||||
interface CursorPreparer {
|
||||
|
||||
/**
|
||||
* Prepare the given cursor (apply limits, skips and so on). Returns th eprepared cursor.
|
||||
* Prepare the given cursor (apply limits, skips and so on). Returns the prepared cursor.
|
||||
*
|
||||
* @param cursor
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -73,9 +73,9 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
DBObject indexOptions = indexDefinition.getIndexOptions();
|
||||
if (indexOptions != null) {
|
||||
collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
|
||||
collection.createIndex(indexDefinition.getIndexKeys(), indexOptions);
|
||||
} else {
|
||||
collection.ensureIndex(indexDefinition.getIndexKeys());
|
||||
collection.createIndex(indexDefinition.getIndexKeys());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -108,10 +108,12 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.IndexOperations#resetIndexCache()
|
||||
*/
|
||||
@Deprecated
|
||||
public void resetIndexCache() {
|
||||
mongoOperations.execute(collectionName, new CollectionCallback<Void>() {
|
||||
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
collection.resetIndexCache();
|
||||
|
||||
ReflectiveDBCollectionInvoker.resetIndexCache(collection);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static java.util.UUID.*;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class DefaultScriptOperations implements ScriptOperations {
|
||||
|
||||
private static final String SCRIPT_COLLECTION_NAME = "system.js";
|
||||
private static final String SCRIPT_NAME_PREFIX = "func_";
|
||||
|
||||
private final MongoOperations mongoOperations;
|
||||
|
||||
/**
|
||||
* Creates new {@link DefaultScriptOperations} using given {@link MongoOperations}.
|
||||
*
|
||||
* @param mongoOperations must not be {@literal null}.
|
||||
*/
|
||||
public DefaultScriptOperations(MongoOperations mongoOperations) {
|
||||
|
||||
Assert.notNull(mongoOperations, "MongoOperations must not be null!");
|
||||
|
||||
this.mongoOperations = mongoOperations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.ExecutableMongoScript)
|
||||
*/
|
||||
@Override
|
||||
public NamedMongoScript register(ExecutableMongoScript script) {
|
||||
return register(new NamedMongoScript(generateScriptName(), script));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#register(org.springframework.data.mongodb.core.script.NamedMongoScript)
|
||||
*/
|
||||
@Override
|
||||
public NamedMongoScript register(NamedMongoScript script) {
|
||||
|
||||
Assert.notNull(script, "Script must not be null!");
|
||||
|
||||
mongoOperations.save(script, SCRIPT_COLLECTION_NAME);
|
||||
return script;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#execute(org.springframework.data.mongodb.core.script.ExecutableMongoScript, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object execute(final ExecutableMongoScript script, final Object... args) {
|
||||
|
||||
Assert.notNull(script, "Script must not be null!");
|
||||
|
||||
return mongoOperations.execute(new DbCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||
return db.eval(script.getCode(), convertScriptArgs(args));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#call(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object call(final String scriptName, final Object... args) {
|
||||
|
||||
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||
|
||||
return mongoOperations.execute(new DbCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public Object doInDB(DB db) throws MongoException, DataAccessException {
|
||||
return db.eval(String.format("%s(%s)", scriptName, convertAndJoinScriptArgs(args)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#exists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(String scriptName) {
|
||||
|
||||
Assert.hasText(scriptName, "ScriptName must not be null or empty!");
|
||||
|
||||
return mongoOperations.exists(query(where("name").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ScriptOperations#getScriptNames()
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getScriptNames() {
|
||||
|
||||
List<NamedMongoScript> scripts = mongoOperations.findAll(NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
|
||||
|
||||
if (CollectionUtils.isEmpty(scripts)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> scriptNames = new HashSet<String>();
|
||||
|
||||
for (NamedMongoScript script : scripts) {
|
||||
scriptNames.add(script.getName());
|
||||
}
|
||||
|
||||
return scriptNames;
|
||||
}
|
||||
|
||||
private Object[] convertScriptArgs(Object... args) {
|
||||
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
return args;
|
||||
}
|
||||
|
||||
List<Object> convertedValues = new ArrayList<Object>(args.length);
|
||||
|
||||
for (Object arg : args) {
|
||||
convertedValues.add(arg instanceof String ? String.format("'%s'", arg) : this.mongoOperations.getConverter()
|
||||
.convertToMongoType(arg));
|
||||
}
|
||||
|
||||
return convertedValues.toArray();
|
||||
}
|
||||
|
||||
private String convertAndJoinScriptArgs(Object... args) {
|
||||
return ObjectUtils.isEmpty(args) ? "" : StringUtils.arrayToCommaDelimitedString(convertScriptArgs(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a valid name for the {@literal JavaScript}. MongoDB requires an id of type String for scripts. Calling
|
||||
* scripts having {@link ObjectId} as id fails. Therefore we create a random UUID without {@code -} (as this won't
|
||||
* work) an prefix the result with {@link #SCRIPT_NAME_PREFIX}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static String generateScriptName() {
|
||||
return SCRIPT_NAME_PREFIX + randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Value object to mitigate different representations of geo command execution results in MongoDB.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Fruitcake - Jeff Coffin (The Inside of the Outside)
|
||||
*/
|
||||
class GeoCommandStatistics {
|
||||
|
||||
private static final GeoCommandStatistics NONE = new GeoCommandStatistics(new BasicDBObject());
|
||||
|
||||
private final DBObject source;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoCommandStatistics} instance with the given source document.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
*/
|
||||
private GeoCommandStatistics(DBObject source) {
|
||||
|
||||
Assert.notNull(source, "Source document must not be null!");
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoCommandStatistics} from the given command result extracting the statistics.
|
||||
*
|
||||
* @param commandResult must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static GeoCommandStatistics from(DBObject commandResult) {
|
||||
|
||||
Assert.notNull(commandResult, "Command result must not be null!");
|
||||
|
||||
Object stats = commandResult.get("stats");
|
||||
return stats == null ? NONE : new GeoCommandStatistics((DBObject) stats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average distance reported by the command result. Mitigating a removal of the field in case the command
|
||||
* didn't return any result introduced in MongoDB 3.2 RC1.
|
||||
*
|
||||
* @return
|
||||
* @see https://jira.mongodb.org/browse/SERVER-21024
|
||||
*/
|
||||
public double getAverageDistance() {
|
||||
|
||||
Object averageDistance = source.get("avgDistance");
|
||||
return averageDistance == null ? Double.NaN : (Double) averageDistance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonModule;
|
||||
import org.springframework.data.web.config.SpringDataWebConfigurationMixin;
|
||||
|
||||
/**
|
||||
* Configuration class to expose {@link GeoJsonModule} as a Spring bean.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SpringDataWebConfigurationMixin
|
||||
public class GeoJsonConfiguration {
|
||||
|
||||
@Bean
|
||||
public GeoJsonModule geoJsonModule() {
|
||||
return new GeoJsonModule();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -20,12 +20,12 @@ import java.util.List;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Index operations on a collection.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface IndexOperations {
|
||||
|
||||
@@ -51,7 +51,11 @@ public interface IndexOperations {
|
||||
|
||||
/**
|
||||
* Clears all indices that have not yet been applied to this collection.
|
||||
*
|
||||
* @deprecated since 1.7. The MongoDB Java driver version 3.0 does no longer support reseting the index cache.
|
||||
* @throws {@link UnsupportedOperationException} when used with MongoDB Java driver version 3.0.
|
||||
*/
|
||||
@Deprecated
|
||||
void resetIndexCache();
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ public class MongoAction {
|
||||
* @param collectionName the collection name, must not be {@literal null} or empty.
|
||||
* @param entityType the POJO that is being operated against
|
||||
* @param document the converted DBObject from the POJO or Spring Update object
|
||||
* @param query the converted DBOjbect from the Spring Query object
|
||||
* @param query the converted DBObject from the Spring Query object
|
||||
*/
|
||||
public MongoAction(WriteConcern defaultWriteConcern, MongoActionOperation mongoActionOperation,
|
||||
String collectionName, Class<?> entityType, DBObject document, DBObject query) {
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
/**
|
||||
* Convenient factory for configuring MongoDB.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||
|
||||
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||
|
||||
private MongoClientOptions mongoClientOptions;
|
||||
private String host;
|
||||
private Integer port;
|
||||
private List<ServerAddress> replicaSetSeeds;
|
||||
private List<MongoCredential> credentials;
|
||||
|
||||
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
|
||||
|
||||
/**
|
||||
* Set the {@link MongoClientOptions} to be used when creating {@link MongoClient}.
|
||||
*
|
||||
* @param mongoClientOptions
|
||||
*/
|
||||
public void setMongoClientOptions(MongoClientOptions mongoClientOptions) {
|
||||
this.mongoClientOptions = mongoClientOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of credentials to be used when creating {@link MongoClient}.
|
||||
*
|
||||
* @param credentials can be {@literal null}.
|
||||
*/
|
||||
public void setCredentials(MongoCredential[] credentials) {
|
||||
this.credentials = filterNonNullElementsAsList(credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of {@link ServerAddress} to build up a replica set for.
|
||||
*
|
||||
* @param replicaSetSeeds can be {@literal null}.
|
||||
*/
|
||||
public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
|
||||
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the host to connect to.
|
||||
*
|
||||
* @param host
|
||||
*/
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the port to connect to.
|
||||
*
|
||||
* @param port
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link PersistenceExceptionTranslator} to use.
|
||||
*
|
||||
* @param exceptionTranslator
|
||||
*/
|
||||
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<? extends Mongo> getObjectType() {
|
||||
return Mongo.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected Mongo createInstance() throws Exception {
|
||||
|
||||
if (mongoClientOptions == null) {
|
||||
mongoClientOptions = MongoClientOptions.builder().build();
|
||||
}
|
||||
|
||||
if (credentials == null) {
|
||||
credentials = Collections.emptyList();
|
||||
}
|
||||
|
||||
return createMongoClient();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected void destroyInstance(Mongo instance) throws Exception {
|
||||
instance.close();
|
||||
}
|
||||
|
||||
private MongoClient createMongoClient() throws UnknownHostException {
|
||||
|
||||
if (!CollectionUtils.isEmpty(replicaSetSeeds)) {
|
||||
return new MongoClient(replicaSetSeeds, credentials, mongoClientOptions);
|
||||
}
|
||||
|
||||
return new MongoClient(createConfiguredOrDefaultServerAddress(), credentials, mongoClientOptions);
|
||||
}
|
||||
|
||||
private ServerAddress createConfiguredOrDefaultServerAddress() throws UnknownHostException {
|
||||
|
||||
ServerAddress defaultAddress = new ServerAddress();
|
||||
|
||||
return new ServerAddress(StringUtils.hasText(host) ? host : defaultAddress.getHost(),
|
||||
port != null ? port.intValue() : defaultAddress.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given array as {@link List} with all {@literal null} elements removed.
|
||||
*
|
||||
* @param elements the elements to filter <T>, can be {@literal null}.
|
||||
* @return a new unmodifiable {@link List#} from the given elements without {@literal null}s.
|
||||
*/
|
||||
private static <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||
|
||||
if (elements == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> candidateElements = new ArrayList<T>();
|
||||
|
||||
for (T element : elements) {
|
||||
if (element != null) {
|
||||
candidateElements.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(candidateElements);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
|
||||
import com.mongodb.DBDecoderFactory;
|
||||
import com.mongodb.DBEncoderFactory;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* A factory bean for construction of a {@link MongoClientOptions} instance.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClientOptions> {
|
||||
|
||||
private static final MongoClientOptions DEFAULT_MONGO_OPTIONS = MongoClientOptions.builder().build();
|
||||
|
||||
private String description = DEFAULT_MONGO_OPTIONS.getDescription();
|
||||
private int minConnectionsPerHost = DEFAULT_MONGO_OPTIONS.getMinConnectionsPerHost();
|
||||
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
|
||||
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
|
||||
.getThreadsAllowedToBlockForConnectionMultiplier();
|
||||
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
|
||||
private int maxConnectionIdleTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionIdleTime();
|
||||
private int maxConnectionLifeTime = DEFAULT_MONGO_OPTIONS.getMaxConnectionLifeTime();
|
||||
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
|
||||
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
|
||||
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
|
||||
private ReadPreference readPreference = DEFAULT_MONGO_OPTIONS.getReadPreference();
|
||||
private DBDecoderFactory dbDecoderFactory = DEFAULT_MONGO_OPTIONS.getDbDecoderFactory();
|
||||
private DBEncoderFactory dbEncoderFactory = DEFAULT_MONGO_OPTIONS.getDbEncoderFactory();
|
||||
private WriteConcern writeConcern = DEFAULT_MONGO_OPTIONS.getWriteConcern();
|
||||
private SocketFactory socketFactory = DEFAULT_MONGO_OPTIONS.getSocketFactory();
|
||||
private boolean cursorFinalizerEnabled = DEFAULT_MONGO_OPTIONS.isCursorFinalizerEnabled();
|
||||
private boolean alwaysUseMBeans = DEFAULT_MONGO_OPTIONS.isAlwaysUseMBeans();
|
||||
private int heartbeatFrequency = DEFAULT_MONGO_OPTIONS.getHeartbeatFrequency();
|
||||
private int minHeartbeatFrequency = DEFAULT_MONGO_OPTIONS.getMinHeartbeatFrequency();
|
||||
private int heartbeatConnectTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatConnectTimeout();
|
||||
private int heartbeatSocketTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatSocketTimeout();
|
||||
private String requiredReplicaSetName = DEFAULT_MONGO_OPTIONS.getRequiredReplicaSetName();
|
||||
|
||||
private boolean ssl;
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
/**
|
||||
* Set the {@link MongoClient} description.
|
||||
*
|
||||
* @param description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum number of connections per host.
|
||||
*
|
||||
* @param minConnectionsPerHost
|
||||
*/
|
||||
public void setMinConnectionsPerHost(int minConnectionsPerHost) {
|
||||
this.minConnectionsPerHost = minConnectionsPerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of connections allowed per host. Will block if run out. Default is 10. System property
|
||||
* {@code MONGO.POOLSIZE} can override
|
||||
*
|
||||
* @param connectionsPerHost
|
||||
*/
|
||||
public void setConnectionsPerHost(int connectionsPerHost) {
|
||||
this.connectionsPerHost = connectionsPerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multiplier for connectionsPerHost for # of threads that can block. Default is 5. If connectionsPerHost is
|
||||
* 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an
|
||||
* exception will be thrown.
|
||||
*
|
||||
* @param threadsAllowedToBlockForConnectionMultiplier
|
||||
*/
|
||||
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
||||
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max wait time of a blocking thread for a connection. Default is 12000 ms (2 minutes)
|
||||
*
|
||||
* @param maxWaitTime
|
||||
*/
|
||||
public void setMaxWaitTime(int maxWaitTime) {
|
||||
this.maxWaitTime = maxWaitTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum idle time for a pooled connection.
|
||||
*
|
||||
* @param maxConnectionIdleTime
|
||||
*/
|
||||
public void setMaxConnectionIdleTime(int maxConnectionIdleTime) {
|
||||
this.maxConnectionIdleTime = maxConnectionIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum life time for a pooled connection.
|
||||
*
|
||||
* @param maxConnectionLifeTime
|
||||
*/
|
||||
public void setMaxConnectionLifeTime(int maxConnectionLifeTime) {
|
||||
this.maxConnectionLifeTime = maxConnectionLifeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connect timeout in milliseconds. 0 is default and infinite.
|
||||
*
|
||||
* @param connectTimeout
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket timeout. 0 is default and infinite.
|
||||
*
|
||||
* @param socketTimeout
|
||||
*/
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the keep alive flag, controls whether or not to have socket keep alive timeout. Defaults to false.
|
||||
*
|
||||
* @param socketKeepAlive
|
||||
*/
|
||||
public void setSocketKeepAlive(boolean socketKeepAlive) {
|
||||
this.socketKeepAlive = socketKeepAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ReadPreference}.
|
||||
*
|
||||
* @param readPreference
|
||||
*/
|
||||
public void setReadPreference(ReadPreference readPreference) {
|
||||
this.readPreference = readPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link WriteConcern} that will be the default value used when asking the {@link MongoDbFactory} for a DB
|
||||
* object.
|
||||
*
|
||||
* @param writeConcern
|
||||
*/
|
||||
public void setWriteConcern(WriteConcern writeConcern) {
|
||||
this.writeConcern = writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param socketFactory
|
||||
*/
|
||||
public void setSocketFactory(SocketFactory socketFactory) {
|
||||
this.socketFactory = socketFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the frequency that the driver will attempt to determine the current state of each server in the cluster.
|
||||
*
|
||||
* @param heartbeatFrequency
|
||||
*/
|
||||
public void setHeartbeatFrequency(int heartbeatFrequency) {
|
||||
this.heartbeatFrequency = heartbeatFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the event that the driver has to frequently re-check a server's availability, it will wait at least this long
|
||||
* since the previous check to avoid wasted effort.
|
||||
*
|
||||
* @param minHeartbeatFrequency
|
||||
*/
|
||||
public void setMinHeartbeatFrequency(int minHeartbeatFrequency) {
|
||||
this.minHeartbeatFrequency = minHeartbeatFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connect timeout for connections used for the cluster heartbeat.
|
||||
*
|
||||
* @param heartbeatConnectTimeout
|
||||
*/
|
||||
public void setHeartbeatConnectTimeout(int heartbeatConnectTimeout) {
|
||||
this.heartbeatConnectTimeout = heartbeatConnectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket timeout for connections used for the cluster heartbeat.
|
||||
*
|
||||
* @param heartbeatSocketTimeout
|
||||
*/
|
||||
public void setHeartbeatSocketTimeout(int heartbeatSocketTimeout) {
|
||||
this.heartbeatSocketTimeout = heartbeatSocketTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the name of the replica set.
|
||||
*
|
||||
* @param requiredReplicaSetName
|
||||
*/
|
||||
public void setRequiredReplicaSetName(String requiredReplicaSetName) {
|
||||
this.requiredReplicaSetName = requiredReplicaSetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This controls if the driver should us an SSL connection. Defaults to |@literal false}.
|
||||
*
|
||||
* @param ssl
|
||||
*/
|
||||
public void setSsl(boolean ssl) {
|
||||
this.ssl = ssl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SSLSocketFactory} to use for the {@literal SSL} connection. If none is configured here,
|
||||
* {@link SSLSocketFactory#getDefault()} will be used.
|
||||
*
|
||||
* @param sslSocketFactory
|
||||
*/
|
||||
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected MongoClientOptions createInstance() throws Exception {
|
||||
|
||||
SocketFactory socketFactoryToUse = ssl ? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory
|
||||
.getDefault()) : this.socketFactory;
|
||||
|
||||
return MongoClientOptions.builder() //
|
||||
.alwaysUseMBeans(this.alwaysUseMBeans) //
|
||||
.connectionsPerHost(this.connectionsPerHost) //
|
||||
.connectTimeout(connectTimeout) //
|
||||
.cursorFinalizerEnabled(cursorFinalizerEnabled) //
|
||||
.dbDecoderFactory(dbDecoderFactory) //
|
||||
.dbEncoderFactory(dbEncoderFactory) //
|
||||
.description(description) //
|
||||
.heartbeatConnectTimeout(heartbeatConnectTimeout) //
|
||||
.heartbeatFrequency(heartbeatFrequency) //
|
||||
.heartbeatSocketTimeout(heartbeatSocketTimeout) //
|
||||
.maxConnectionIdleTime(maxConnectionIdleTime) //
|
||||
.maxConnectionLifeTime(maxConnectionLifeTime) //
|
||||
.maxWaitTime(maxWaitTime) //
|
||||
.minConnectionsPerHost(minConnectionsPerHost) //
|
||||
.minHeartbeatFrequency(minHeartbeatFrequency) //
|
||||
.readPreference(readPreference) //
|
||||
.requiredReplicaSetName(requiredReplicaSetName) //
|
||||
.socketFactory(socketFactoryToUse) //
|
||||
.socketKeepAlive(socketKeepAlive) //
|
||||
.socketTimeout(socketTimeout) //
|
||||
.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier) //
|
||||
.writeConcern(writeConcern).build();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return MongoClientOptions.class;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -18,12 +18,13 @@ package org.springframework.data.mongodb.core;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
||||
@@ -34,6 +35,7 @@ import com.mongodb.Mongo;
|
||||
* @author Oliver Gierke
|
||||
* @author Randy Watler
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.0
|
||||
*/
|
||||
public abstract class MongoDbUtils {
|
||||
@@ -43,9 +45,7 @@ public abstract class MongoDbUtils {
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private MongoDbUtils() {
|
||||
|
||||
}
|
||||
private MongoDbUtils() {}
|
||||
|
||||
/**
|
||||
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
|
||||
@@ -65,11 +65,24 @@ public abstract class MongoDbUtils {
|
||||
* @param databaseName the database name, must not be {@literal null} or empty.
|
||||
* @param credentials the credentials to use, must not be {@literal null}.
|
||||
* @return the {@link DB} connection
|
||||
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||
* {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||
return getDB(mongo, databaseName, credentials, databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mongo
|
||||
* @param databaseName
|
||||
* @param credentials
|
||||
* @param authenticationDatabaseName
|
||||
* @return
|
||||
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||
* {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
String authenticationDatabaseName) {
|
||||
|
||||
@@ -109,22 +122,9 @@ public abstract class MongoDbUtils {
|
||||
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
|
||||
|
||||
DB db = mongo.getDB(databaseName);
|
||||
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
|
||||
|
||||
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
||||
|
||||
synchronized (authDb) {
|
||||
|
||||
if (credentialsGiven && !authDb.isAuthenticated()) {
|
||||
|
||||
String username = credentials.getUsername();
|
||||
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
||||
|
||||
if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
|
||||
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
||||
+ credentials.toString(), databaseName, credentials);
|
||||
}
|
||||
}
|
||||
if (!(mongo instanceof MongoClient) && requiresAuthDbAuthentication(credentials)) {
|
||||
ReflectiveDbInvoker.authenticate(mongo, db, credentials, authenticationDatabaseName);
|
||||
}
|
||||
|
||||
// TX sync active, bind new database to thread
|
||||
@@ -181,16 +181,36 @@ public abstract class MongoDbUtils {
|
||||
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
|
||||
*
|
||||
* @param db the DB to close (may be <code>null</code>)
|
||||
* @deprecated since 1.7. The main use case for this method is to ensure that applications can read their own
|
||||
* unacknowledged writes, but this is no longer so prevalent since the MongoDB Java driver version 3
|
||||
* started defaulting to acknowledged writes.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void closeDB(DB db) {
|
||||
|
||||
if (db != null) {
|
||||
LOGGER.debug("Closing Mongo DB object");
|
||||
try {
|
||||
db.requestDone();
|
||||
ReflectiveDbInvoker.requestDone(db);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if credentials present. In case we're using a mongo-java-driver version 3 or above we do not have the need
|
||||
* for authentication as the auth data has to be provided within the MongoClient
|
||||
*
|
||||
* @param credentials
|
||||
* @return
|
||||
*/
|
||||
private static boolean requiresAuthDbAuthentication(UserCredentials credentials) {
|
||||
|
||||
if (credentials == null || !credentials.hasUsername()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !MongoClientVersion.isMongo3Driver();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,23 +15,21 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.mongodb.MongoCursorNotFoundException;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.MongoException.CursorNotFound;
|
||||
import com.mongodb.MongoException.DuplicateKey;
|
||||
import com.mongodb.MongoException.Network;
|
||||
import com.mongodb.MongoInternalException;
|
||||
import com.mongodb.MongoServerSelectionException;
|
||||
import com.mongodb.MongoSocketException;
|
||||
import com.mongodb.MongoTimeoutException;
|
||||
|
||||
/**
|
||||
* Simple {@link PersistenceExceptionTranslator} for Mongo. Convert the given runtime exception to an appropriate
|
||||
@@ -40,9 +38,23 @@ import com.mongodb.MongoTimeoutException;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Michal Vich
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
private static final Set<String> DULICATE_KEY_EXCEPTIONS = new HashSet<String>(Arrays.asList(
|
||||
"MongoException.DuplicateKey", "DuplicateKeyException"));
|
||||
|
||||
private static final Set<String> RESOURCE_FAILURE_EXCEPTIONS = new HashSet<String>(Arrays.asList(
|
||||
"MongoException.Network", "MongoSocketException", "MongoException.CursorNotFound",
|
||||
"MongoCursorNotFoundException", "MongoServerSelectionException", "MongoTimeoutException"));
|
||||
|
||||
private static final Set<String> RESOURCE_USAGE_EXCEPTIONS = new HashSet<String>(
|
||||
Arrays.asList("MongoInternalException"));
|
||||
|
||||
private static final Set<String> DATA_INTEGRETY_EXCEPTIONS = new HashSet<String>(
|
||||
Arrays.asList("WriteConcernException"));
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
@@ -51,30 +63,24 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
|
||||
// Check for well-known MongoException subclasses.
|
||||
|
||||
if (ex instanceof DuplicateKey || ex instanceof DuplicateKeyException) {
|
||||
String exception = ClassUtils.getShortName(ClassUtils.getUserClass(ex.getClass()));
|
||||
|
||||
if (DULICATE_KEY_EXCEPTIONS.contains(exception)) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (ex instanceof Network || ex instanceof MongoSocketException) {
|
||||
if (RESOURCE_FAILURE_EXCEPTIONS.contains(exception)) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (ex instanceof CursorNotFound || ex instanceof MongoCursorNotFoundException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (ex instanceof MongoServerSelectionException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (ex instanceof MongoTimeoutException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (ex instanceof MongoInternalException) {
|
||||
if (RESOURCE_USAGE_EXCEPTIONS.contains(exception)) {
|
||||
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (DATA_INTEGRETY_EXCEPTIONS.contains(exception)) {
|
||||
return new DataIntegrityViolationException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
// All other MongoExceptions
|
||||
if (ex instanceof MongoException) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -20,9 +20,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
@@ -40,12 +38,14 @@ import com.mongodb.WriteConcern;
|
||||
* @author Graeme Rocher
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.0
|
||||
* @deprecated since 1.7. Please use {@link MongoClientFactoryBean} instead.
|
||||
*/
|
||||
public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, DisposableBean,
|
||||
PersistenceExceptionTranslator {
|
||||
@Deprecated
|
||||
public class MongoFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||
|
||||
private Mongo mongo;
|
||||
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||
|
||||
private MongoOptions mongoOptions;
|
||||
private String host;
|
||||
@@ -53,9 +53,11 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
private WriteConcern writeConcern;
|
||||
private List<ServerAddress> replicaSetSeeds;
|
||||
private List<ServerAddress> replicaPair;
|
||||
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
|
||||
|
||||
private PersistenceExceptionTranslator exceptionTranslator = new MongoExceptionTranslator();
|
||||
|
||||
/**
|
||||
* @param mongoOptions
|
||||
*/
|
||||
public void setMongoOptions(MongoOptions mongoOptions) {
|
||||
this.mongoOptions = mongoOptions;
|
||||
}
|
||||
@@ -66,7 +68,6 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
|
||||
*
|
||||
* @param replicaPair
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -75,30 +76,19 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
}
|
||||
|
||||
/**
|
||||
* @param elements the elements to filter <T>
|
||||
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
||||
* Configures the host to connect to.
|
||||
*
|
||||
* @param host
|
||||
*/
|
||||
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||
|
||||
if (elements == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> candidateElements = new ArrayList<T>();
|
||||
|
||||
for (T element : elements) {
|
||||
if (element != null) {
|
||||
candidateElements.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(candidateElements);
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the port to connect to.
|
||||
*
|
||||
* @param port
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
@@ -112,12 +102,13 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
this.writeConcern = writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link PersistenceExceptionTranslator} to use.
|
||||
*
|
||||
* @param exceptionTranslator can be {@literal null}.
|
||||
*/
|
||||
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
}
|
||||
|
||||
public Mongo getObject() throws Exception {
|
||||
return mongo;
|
||||
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,14 +119,6 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
return Mongo.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
@@ -146,10 +129,10 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
@Override
|
||||
protected Mongo createInstance() throws Exception {
|
||||
|
||||
Mongo mongo;
|
||||
ServerAddress defaultOptions = new ServerAddress();
|
||||
@@ -175,18 +158,42 @@ public class MongoFactoryBean implements FactoryBean<Mongo>, InitializingBean, D
|
||||
mongo.setWriteConcern(writeConcern);
|
||||
}
|
||||
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
private boolean isNullOrEmpty(Collection<?> elements) {
|
||||
return elements == null || elements.isEmpty();
|
||||
return mongo;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
this.mongo.close();
|
||||
@Override
|
||||
protected void destroyInstance(Mongo mongo) throws Exception {
|
||||
mongo.close();
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(Collection<?> elements) {
|
||||
return elements == null || elements.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given array as {@link List} with all {@literal null} elements removed.
|
||||
*
|
||||
* @param elements the elements to filter <T>
|
||||
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
||||
*/
|
||||
private static <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||
|
||||
if (elements == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> candidateElements = new ArrayList<T>();
|
||||
|
||||
for (T element : elements) {
|
||||
if (element != null) {
|
||||
candidateElements.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(candidateElements);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -33,10 +33,14 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
|
||||
import com.mongodb.CommandResult;
|
||||
import com.mongodb.Cursor;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.WriteResult;
|
||||
|
||||
/**
|
||||
@@ -85,9 +89,23 @@ public interface MongoOperations {
|
||||
*
|
||||
* @param command a MongoDB command
|
||||
* @param options query options to use
|
||||
* @deprecated since 1.7. Please use {@link #executeCommand(DBObject, ReadPreference)}, as the MongoDB Java driver
|
||||
* version 3 no longer supports this operation.
|
||||
*/
|
||||
@Deprecated
|
||||
CommandResult executeCommand(DBObject command, int options);
|
||||
|
||||
/**
|
||||
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's data
|
||||
* access exception hierarchy.
|
||||
*
|
||||
* @param command a MongoDB command, must not be {@literal null}.
|
||||
* @param readPreference read preferences to use, can be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
CommandResult executeCommand(DBObject command, ReadPreference readPreference);
|
||||
|
||||
/**
|
||||
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
|
||||
*
|
||||
@@ -143,9 +161,26 @@ public interface MongoOperations {
|
||||
* @param <T> return type
|
||||
* @param action callback that specified the MongoDB actions to perform on the DB instance
|
||||
* @return a result object returned by the action or <tt>null</tt>
|
||||
* @deprecated since 1.7 as the MongoDB Java driver version 3 does not longer support request boundaries via
|
||||
* {@link DB#requestStart()} and {@link DB#requestDone()}.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T executeInSession(DbCallback<T> action);
|
||||
|
||||
/**
|
||||
* Executes the given {@link Query} on the entity collection of the specified {@code entityType} backed by a Mongo DB
|
||||
* {@link Cursor}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query
|
||||
* @param entityType
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
<T> CloseableIterator<T> stream(Query query, Class<T> entityType);
|
||||
|
||||
/**
|
||||
* Create an uncapped collection with a name based on the provided entity class.
|
||||
*
|
||||
@@ -155,7 +190,7 @@ public interface MongoOperations {
|
||||
<T> DBCollection createCollection(Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Create a collect with a name based on the provided entity class using the options.
|
||||
* Create a collection with a name based on the provided entity class using the options.
|
||||
*
|
||||
* @param entityClass class that determines the collection to create
|
||||
* @param collectionOptions options to use when creating the collection.
|
||||
@@ -172,7 +207,7 @@ public interface MongoOperations {
|
||||
DBCollection createCollection(String collectionName);
|
||||
|
||||
/**
|
||||
* Create a collect with the provided name and options.
|
||||
* Create a collection with the provided name and options.
|
||||
*
|
||||
* @param collectionName name of the collection
|
||||
* @param collectionOptions options to use when creating the collection.
|
||||
@@ -249,6 +284,14 @@ public interface MongoOperations {
|
||||
*/
|
||||
IndexOperations indexOps(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Returns the {@link ScriptOperations} that can be performed on {@link com.mongodb.DB} level.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
ScriptOperations scriptOps();
|
||||
|
||||
/**
|
||||
* Query for a list of objects of type T from the collection used by the entity class.
|
||||
* <p/>
|
||||
@@ -415,7 +458,9 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Will consider entity mapping
|
||||
* information to determine the collection the query is ran against.
|
||||
* information to determine the collection the query is ran against. Note, that MongoDB limits the number of results
|
||||
* by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a particular number of
|
||||
* results.
|
||||
*
|
||||
* @param near must not be {@literal null}.
|
||||
* @param entityClass must not be {@literal null}.
|
||||
@@ -424,7 +469,9 @@ public interface MongoOperations {
|
||||
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}.
|
||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Note, that MongoDB limits the
|
||||
* number of results by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a
|
||||
* particular number of results.
|
||||
*
|
||||
* @param near must not be {@literal null}.
|
||||
* @param entityClass must not be {@literal null}.
|
||||
@@ -652,14 +699,28 @@ public interface MongoOperations {
|
||||
long count(Query query, Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Returns the number of documents for the given {@link Query} querying the given collection.
|
||||
* Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query}
|
||||
* must solely consist of document field references as we lack type information to map potential property references
|
||||
* onto document fields. TO make sure the query gets mapped, use {@link #count(Query, Class, String)}.
|
||||
*
|
||||
* @param query
|
||||
* @param collectionName must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @see #count(Query, Class, String)
|
||||
*/
|
||||
long count(Query query, String collectionName);
|
||||
|
||||
/**
|
||||
* Returns the number of documents for the given {@link Query} by querying the given collection using the given entity
|
||||
* class to map the given {@link Query}.
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @param collectionName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
long count(Query query, Class<?> entityClass, String collectionName);
|
||||
|
||||
/**
|
||||
* Insert the object into the collection for the entity type of the object to save.
|
||||
* <p/>
|
||||
@@ -941,4 +1002,5 @@ public interface MongoOperations {
|
||||
* @return
|
||||
*/
|
||||
MongoConverter getConverter();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -17,41 +17,48 @@ package org.springframework.data.mongodb.core;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.MongoOptions;
|
||||
|
||||
/**
|
||||
* A factory bean for construction of a {@link MongoOptions} instance.
|
||||
*
|
||||
* A factory bean for construction of a {@link MongoOptions} instance. In case used with MongoDB Java driver version 3
|
||||
* porperties not suppprted by the driver will be ignored.
|
||||
*
|
||||
* @author Graeme Rocher
|
||||
* @author Mark Pollack
|
||||
* @author Mike Saavedra
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @deprecated since 1.7. Please use {@link MongoClientOptionsFactoryBean} instead.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, InitializingBean {
|
||||
@Deprecated
|
||||
public class MongoOptionsFactoryBean extends AbstractFactoryBean<MongoOptions> {
|
||||
|
||||
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
|
||||
|
||||
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.connectionsPerHost;
|
||||
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS.threadsAllowedToBlockForConnectionMultiplier;
|
||||
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.maxWaitTime;
|
||||
private int connectTimeout = DEFAULT_MONGO_OPTIONS.connectTimeout;
|
||||
private int socketTimeout = DEFAULT_MONGO_OPTIONS.socketTimeout;
|
||||
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.socketKeepAlive;
|
||||
private boolean autoConnectRetry = DEFAULT_MONGO_OPTIONS.autoConnectRetry;
|
||||
private long maxAutoConnectRetryTime = DEFAULT_MONGO_OPTIONS.maxAutoConnectRetryTime;
|
||||
private int writeNumber = DEFAULT_MONGO_OPTIONS.w;
|
||||
private int writeTimeout = DEFAULT_MONGO_OPTIONS.wtimeout;
|
||||
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.fsync;
|
||||
private boolean slaveOk = DEFAULT_MONGO_OPTIONS.slaveOk;
|
||||
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
|
||||
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
|
||||
.getThreadsAllowedToBlockForConnectionMultiplier();
|
||||
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
|
||||
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
|
||||
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
|
||||
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
|
||||
private int writeNumber = DEFAULT_MONGO_OPTIONS.getW();
|
||||
private int writeTimeout = DEFAULT_MONGO_OPTIONS.getWtimeout();
|
||||
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.isFsync();
|
||||
|
||||
private boolean autoConnectRetry = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getAutoConnectRetry(DEFAULT_MONGO_OPTIONS) : false;
|
||||
private long maxAutoConnectRetryTime = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getMaxAutoConnectRetryTime(DEFAULT_MONGO_OPTIONS) : -1;
|
||||
private boolean slaveOk = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getSlaveOk(DEFAULT_MONGO_OPTIONS) : false;
|
||||
|
||||
private boolean ssl;
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
private MongoOptions options;
|
||||
|
||||
/**
|
||||
* Configures the maximum number of connections allowed per host until we will block.
|
||||
*
|
||||
@@ -144,7 +151,10 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
||||
|
||||
/**
|
||||
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
|
||||
*
|
||||
* @deprecated since 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
||||
this.autoConnectRetry = autoConnectRetry;
|
||||
}
|
||||
@@ -154,7 +164,9 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
||||
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
|
||||
*
|
||||
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
|
||||
* @deprecated since 1.7
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
|
||||
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
||||
}
|
||||
@@ -163,7 +175,9 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
||||
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
|
||||
*
|
||||
* @param slaveOk true if the driver should read from secondaries or slaves.
|
||||
* @deprecated since 1.7
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSlaveOk(boolean slaveOk) {
|
||||
this.slaveOk = slaveOk;
|
||||
}
|
||||
@@ -194,40 +208,41 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
@Override
|
||||
protected MongoOptions createInstance() throws Exception {
|
||||
|
||||
if (MongoClientVersion.isMongo3Driver()) {
|
||||
throw new IllegalArgumentException(
|
||||
String
|
||||
.format("Usage of 'mongo-options' is no longer supported for MongoDB Java driver version 3 and above. Please use 'mongo-client-options' and refer to chapter 'MongoDB 3.0 Support' for details."));
|
||||
}
|
||||
|
||||
MongoOptions options = new MongoOptions();
|
||||
|
||||
options.connectionsPerHost = connectionsPerHost;
|
||||
options.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||
options.maxWaitTime = maxWaitTime;
|
||||
options.connectTimeout = connectTimeout;
|
||||
options.socketTimeout = socketTimeout;
|
||||
options.socketKeepAlive = socketKeepAlive;
|
||||
options.autoConnectRetry = autoConnectRetry;
|
||||
options.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
||||
options.slaveOk = slaveOk;
|
||||
options.w = writeNumber;
|
||||
options.wtimeout = writeTimeout;
|
||||
options.fsync = writeFsync;
|
||||
options.setConnectionsPerHost(connectionsPerHost);
|
||||
options.setThreadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
|
||||
options.setMaxWaitTime(maxWaitTime);
|
||||
options.setConnectTimeout(connectTimeout);
|
||||
options.setSocketTimeout(socketTimeout);
|
||||
options.setSocketKeepAlive(socketKeepAlive);
|
||||
|
||||
options.setW(writeNumber);
|
||||
options.setWtimeout(writeTimeout);
|
||||
options.setFsync(writeFsync);
|
||||
|
||||
if (ssl) {
|
||||
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
ReflectiveMongoOptionsInvoker.setAutoConnectRetry(options, autoConnectRetry);
|
||||
ReflectiveMongoOptionsInvoker.setMaxAutoConnectRetryTime(options, maxAutoConnectRetryTime);
|
||||
ReflectiveMongoOptionsInvoker.setSlaveOk(options, slaveOk);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
public MongoOptions getObject() {
|
||||
return this.options;
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,12 +252,4 @@ public class MongoOptionsFactoryBean implements FactoryBean<MongoOptions>, Initi
|
||||
public Class<?> getObjectType() {
|
||||
return MongoOptions.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -95,14 +95,19 @@ import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.jca.cci.core.ConnectionCallback;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.Bytes;
|
||||
import com.mongodb.CommandResult;
|
||||
import com.mongodb.Cursor;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
@@ -131,6 +136,8 @@ import com.mongodb.util.JSONParseException;
|
||||
* @author Thomas Darimont
|
||||
* @author Chuong Ngo
|
||||
* @author Christoph Strobl
|
||||
* @author Doménique Tilleuil
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
@@ -312,6 +319,33 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return this.mongoConverter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#executeAsStream(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> CloseableIterator<T> stream(final Query query, final Class<T> entityType) {
|
||||
|
||||
return execute(entityType, new CollectionCallback<CloseableIterator<T>>() {
|
||||
|
||||
@Override
|
||||
public CloseableIterator<T> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityType);
|
||||
|
||||
DBObject mappedFields = queryMapper.getMappedFields(query.getFieldsObject(), persistentEntity);
|
||||
DBObject mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), persistentEntity);
|
||||
|
||||
DBCursor cursor = collection.find(mappedQuery, mappedFields);
|
||||
QueryCursorPreparer cursorPreparer = new QueryCursorPreparer(query, entityType);
|
||||
|
||||
ReadDbObjectCallback<T> readCallback = new ReadDbObjectCallback<T>(mongoConverter, entityType);
|
||||
|
||||
return new CloseableIterableCursorAdapter<T>(cursorPreparer.prepare(cursor), exceptionTranslator, readCallback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getCollectionName(Class<?> entityClass) {
|
||||
return this.determineCollectionName(entityClass);
|
||||
}
|
||||
@@ -332,26 +366,41 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, int)
|
||||
*/
|
||||
@Deprecated
|
||||
public CommandResult executeCommand(final DBObject command, final int options) {
|
||||
return executeCommand(command, (options & Bytes.QUERYOPTION_SLAVEOK) != 0 ? ReadPreference.secondaryPreferred()
|
||||
: ReadPreference.primary());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#executeCommand(com.mongodb.DBObject, com.mongodb.ReadPreference)
|
||||
*/
|
||||
public CommandResult executeCommand(final DBObject command, final ReadPreference readPreference) {
|
||||
|
||||
Assert.notNull(command, "Command must not be null!");
|
||||
|
||||
CommandResult result = execute(new DbCallback<CommandResult>() {
|
||||
public CommandResult doInDB(DB db) throws MongoException, DataAccessException {
|
||||
return db.command(command, options);
|
||||
return readPreference != null ? db.command(command, readPreference) : db.command(command);
|
||||
}
|
||||
});
|
||||
|
||||
logCommandExecutionError(command, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void logCommandExecutionError(final DBObject command, CommandResult result) {
|
||||
|
||||
String error = result.getErrorMessage();
|
||||
|
||||
if (error != null) {
|
||||
// TODO: DATADOC-204 allow configuration of logging level / throw
|
||||
// throw new
|
||||
// InvalidDataAccessApiUsageException("Command execution of " +
|
||||
// command.toString() + " failed: " + error);
|
||||
LOGGER.warn("Command execution of " + command.toString() + " failed: " + error);
|
||||
LOGGER.warn("Command execution of {} failed: {}", command.toString(), error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,8 +428,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DBObject fieldsObject = query.getFieldsObject();
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("Executing query: %s sort: %s fields: %s in collection: %s",
|
||||
serializeToJsonSafely(queryObject), sortObject, fieldsObject, collectionName));
|
||||
LOGGER.debug("Executing query: {} sort: {} fields: {} in collection: {}", serializeToJsonSafely(queryObject),
|
||||
sortObject, fieldsObject, collectionName);
|
||||
}
|
||||
|
||||
this.executeQueryInternal(new FindCallback(queryObject, fieldsObject), preparer, dch, collectionName);
|
||||
@@ -394,7 +443,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DB db = this.getDb();
|
||||
return action.doInDB(db);
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,18 +459,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DBCollection collection = getAndPrepareCollection(getDb(), collectionName);
|
||||
return callback.doInCollection(collection);
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#executeInSession(org.springframework.data.mongodb.core.DbCallback)
|
||||
*/
|
||||
@Deprecated
|
||||
public <T> T executeInSession(final DbCallback<T> action) {
|
||||
|
||||
return execute(new DbCallback<T>() {
|
||||
public T doInDB(DB db) throws MongoException, DataAccessException {
|
||||
try {
|
||||
db.requestStart();
|
||||
ReflectiveDbInvoker.requestStart(db);
|
||||
return action.doInDB(db);
|
||||
} finally {
|
||||
db.requestDone();
|
||||
ReflectiveDbInvoker.requestDone(db);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -472,7 +527,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
collection.drop();
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Dropped collection [" + collection.getFullName() + "]");
|
||||
LOGGER.debug("Dropped collection [{}]", collection.getFullName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -487,6 +542,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#scriptOps()
|
||||
*/
|
||||
@Override
|
||||
public ScriptOperations scriptOps() {
|
||||
return new DefaultScriptOperations(this);
|
||||
}
|
||||
|
||||
// Find methods that take a Query to express the query and that return a single object.
|
||||
|
||||
public <T> T findOne(Query query, Class<T> entityClass) {
|
||||
@@ -564,10 +628,22 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
String collection = StringUtils.hasText(collectionName) ? collectionName : determineCollectionName(entityClass);
|
||||
BasicDBObject command = new BasicDBObject("geoNear", collection);
|
||||
command.putAll(near.toDBObject());
|
||||
DBObject nearDbObject = near.toDBObject();
|
||||
|
||||
CommandResult commandResult = executeCommand(command);
|
||||
BasicDBObject command = new BasicDBObject("geoNear", collection);
|
||||
command.putAll(nearDbObject);
|
||||
|
||||
if (nearDbObject.containsField("query")) {
|
||||
DBObject query = (DBObject) nearDbObject.get("query");
|
||||
command.put("query", queryMapper.getMappedObject(query, getPersistentEntity(entityClass)));
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Executing geoNear using: {} for class: {} in collection: {}", serializeToJsonSafely(command),
|
||||
entityClass, collectionName);
|
||||
}
|
||||
|
||||
CommandResult commandResult = executeCommand(command, this.readPreference);
|
||||
List<Object> results = (List<Object>) commandResult.get("results");
|
||||
results = results == null ? Collections.emptyList() : results;
|
||||
|
||||
@@ -597,9 +673,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return new GeoResults<T>(result, near.getMetric());
|
||||
}
|
||||
|
||||
DBObject stats = (DBObject) commandResult.get("stats");
|
||||
double averageDistance = stats == null ? 0 : (Double) stats.get("avgDistance");
|
||||
return new GeoResults<T>(result, new Distance(averageDistance, near.getMetric()));
|
||||
GeoCommandStatistics stats = GeoCommandStatistics.from(commandResult);
|
||||
return new GeoResults<T>(result, new Distance(stats.getAverageDistance(), near.getMetric()));
|
||||
}
|
||||
|
||||
public <T> T findAndModify(Query query, Update update, Class<T> entityClass) {
|
||||
@@ -642,7 +717,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return count(query, null, collectionName);
|
||||
}
|
||||
|
||||
private long count(Query query, Class<?> entityClass, String collectionName) {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.MongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||
*/
|
||||
public long count(Query query, Class<?> entityClass, String collectionName) {
|
||||
|
||||
Assert.hasText(collectionName);
|
||||
final DBObject dbObject = query == null ? null : queryMapper.getMappedObject(query.getQueryObject(),
|
||||
@@ -695,13 +774,29 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Prepare the WriteConcern before any processing is done using it. This allows a convenient way to apply custom
|
||||
* settings in sub-classes.
|
||||
* settings in sub-classes. <br />
|
||||
* In case of using MongoDB Java driver version 3 the returned {@link WriteConcern} will be defaulted to
|
||||
* {@link WriteConcern#ACKNOWLEDGED} when {@link WriteResultChecking} is set to {@link WriteResultChecking#EXCEPTION}.
|
||||
*
|
||||
* @param writeConcern any WriteConcern already configured or null
|
||||
* @return The prepared WriteConcern or null
|
||||
*/
|
||||
protected WriteConcern prepareWriteConcern(MongoAction mongoAction) {
|
||||
return writeConcernResolver.resolve(mongoAction);
|
||||
|
||||
WriteConcern wc = writeConcernResolver.resolve(mongoAction);
|
||||
return potentiallyForceAcknowledgedWrite(wc);
|
||||
}
|
||||
|
||||
private WriteConcern potentiallyForceAcknowledgedWrite(WriteConcern wc) {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(WriteResultChecking.EXCEPTION, writeResultChecking)
|
||||
&& MongoClientVersion.isMongo3Driver()) {
|
||||
if (wc == null || wc.getWObject() == null
|
||||
|| (wc.getWObject() instanceof Number && ((Number) wc.getWObject()).intValue() < 1)) {
|
||||
return WriteConcern.ACKNOWLEDGED;
|
||||
}
|
||||
}
|
||||
return wc;
|
||||
}
|
||||
|
||||
protected <T> void doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
|
||||
@@ -765,27 +860,33 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
protected <T> void doInsertAll(Collection<? extends T> listToSave, MongoWriter<T> writer) {
|
||||
Map<String, List<T>> objs = new HashMap<String, List<T>>();
|
||||
|
||||
for (T o : listToSave) {
|
||||
Map<String, List<T>> elementsByCollection = new HashMap<String, List<T>>();
|
||||
|
||||
for (T element : listToSave) {
|
||||
|
||||
if (element == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(element.getClass());
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(o.getClass());
|
||||
if (entity == null) {
|
||||
throw new InvalidDataAccessApiUsageException("No Persitent Entity information found for the class "
|
||||
+ o.getClass().getName());
|
||||
throw new InvalidDataAccessApiUsageException("No PersistentEntity information found for " + element.getClass());
|
||||
}
|
||||
|
||||
String collection = entity.getCollection();
|
||||
List<T> collectionElements = elementsByCollection.get(collection);
|
||||
|
||||
List<T> objList = objs.get(collection);
|
||||
if (null == objList) {
|
||||
objList = new ArrayList<T>();
|
||||
objs.put(collection, objList);
|
||||
if (null == collectionElements) {
|
||||
collectionElements = new ArrayList<T>();
|
||||
elementsByCollection.put(collection, collectionElements);
|
||||
}
|
||||
objList.add(o);
|
||||
|
||||
collectionElements.add(element);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, List<T>> entry : objs.entrySet()) {
|
||||
for (Map.Entry<String, List<T>> entry : elementsByCollection.entrySet()) {
|
||||
doInsertBatch(entry.getKey(), entry.getValue(), this.mongoConverter);
|
||||
}
|
||||
}
|
||||
@@ -893,9 +994,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
protected Object insertDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Inserting DBObject containing fields: " + dbDoc.keySet() + " in collection: " + collectionName);
|
||||
LOGGER.debug("Inserting DBObject containing fields: {} in collection: {}", dbDoc.keySet(), collectionName);
|
||||
}
|
||||
|
||||
return execute(collectionName, new CollectionCallback<Object>() {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT, collectionName,
|
||||
@@ -915,8 +1018,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Inserting list of DBObjects containing " + dbDocList.size() + " items");
|
||||
LOGGER.debug("Inserting list of DBObjects containing {} items", dbDocList.size());
|
||||
}
|
||||
|
||||
execute(collectionName, new CollectionCallback<Void>() {
|
||||
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.INSERT_LIST, collectionName, null,
|
||||
@@ -943,9 +1047,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
protected Object saveDBObject(final String collectionName, final DBObject dbDoc, final Class<?> entityClass) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Saving DBObject containing fields: " + dbDoc.keySet());
|
||||
LOGGER.debug("Saving DBObject containing fields: {}", dbDoc.keySet());
|
||||
}
|
||||
|
||||
return execute(collectionName, new CollectionCallback<Object>() {
|
||||
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass,
|
||||
@@ -1011,8 +1117,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
update.getUpdateObject(), entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("Calling update using query: %s and update: %s in collection: %s",
|
||||
serializeToJsonSafely(queryObj), serializeToJsonSafely(updateObj), collectionName));
|
||||
LOGGER.debug("Calling update using query: {} and update: {} in collection: {}",
|
||||
serializeToJsonSafely(queryObj), serializeToJsonSafely(updateObj), collectionName);
|
||||
}
|
||||
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName,
|
||||
@@ -1022,7 +1128,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
: collection.update(queryObj, updateObj, upsert, multi, writeConcernToUse);
|
||||
|
||||
if (entity != null && entity.hasVersionProperty() && !multi) {
|
||||
if (writeResult.getN() == 0 && dbObjectContainsVersionProperty(queryObj, entity)) {
|
||||
if (ReflectiveWriteResultInvoker.wasAcknowledged(writeResult) && writeResult.getN() == 0
|
||||
&& dbObjectContainsVersionProperty(queryObj, entity)) {
|
||||
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
|
||||
+ updateObj.toMap().toString() + " to collection " + collectionName);
|
||||
}
|
||||
@@ -1189,8 +1296,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Remove using query: {} in collection: {}.",
|
||||
new Object[] { serializeToJsonSafely(dboq), collection.getName() });
|
||||
LOGGER.debug("Remove using query: {} in collection: {}.", new Object[] { serializeToJsonSafely(dboq),
|
||||
collection.getName() });
|
||||
}
|
||||
|
||||
WriteResult wr = writeConcernToUse == null ? collection.remove(dboq) : collection.remove(dboq,
|
||||
@@ -1238,25 +1345,24 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
String mapFunc = replaceWithResourceIfNecessary(mapFunction);
|
||||
String reduceFunc = replaceWithResourceIfNecessary(reduceFunction);
|
||||
DBCollection inputCollection = getCollection(inputCollectionName);
|
||||
|
||||
MapReduceCommand command = new MapReduceCommand(inputCollection, mapFunc, reduceFunc,
|
||||
mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), null);
|
||||
mapReduceOptions.getOutputCollection(), mapReduceOptions.getOutputType(), query == null
|
||||
|| query.getQueryObject() == null ? null : queryMapper.getMappedObject(query.getQueryObject(), null));
|
||||
|
||||
DBObject commandObject = copyQuery(query, copyMapReduceOptions(mapReduceOptions, command));
|
||||
copyMapReduceOptionsToCommand(query, mapReduceOptions, command);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Executing MapReduce on collection [" + command.getInput() + "], mapFunction [" + mapFunc
|
||||
+ "], reduceFunction [" + reduceFunc + "]");
|
||||
LOGGER.debug("Executing MapReduce on collection [{}], mapFunction [{}], reduceFunction [{}]", command.getInput(),
|
||||
mapFunc, reduceFunc);
|
||||
}
|
||||
|
||||
CommandResult commandResult = command.getOutputType() == MapReduceCommand.OutputType.INLINE ? executeCommand(
|
||||
commandObject, getDb().getOptions()) : executeCommand(commandObject);
|
||||
handleCommandError(commandResult, commandObject);
|
||||
MapReduceOutput mapReduceOutput = inputCollection.mapReduce(command);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(commandObject));
|
||||
LOGGER.debug("MapReduce command result = [{}]", serializeToJsonSafely(mapReduceOutput.results()));
|
||||
}
|
||||
|
||||
MapReduceOutput mapReduceOutput = new MapReduceOutput(inputCollection, commandObject, commandResult);
|
||||
List<T> mappedResults = new ArrayList<T>();
|
||||
DbObjectCallback<T> callback = new ReadDbObjectCallback<T>(mongoConverter, entityClass);
|
||||
|
||||
@@ -1264,7 +1370,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
mappedResults.add(callback.doWith(dbObject));
|
||||
}
|
||||
|
||||
return new MapReduceResults<T>(mappedResults, commandResult);
|
||||
return new MapReduceResults<T>(mappedResults, mapReduceOutput);
|
||||
}
|
||||
|
||||
public <T> GroupByResults<T> group(String inputCollectionName, GroupBy groupBy, Class<T> entityClass) {
|
||||
@@ -1418,7 +1524,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
LOGGER.debug("Executing aggregation: {}", serializeToJsonSafely(command));
|
||||
}
|
||||
|
||||
CommandResult commandResult = executeCommand(command);
|
||||
CommandResult commandResult = executeCommand(command, this.readPreference);
|
||||
handleCommandError(commandResult, command);
|
||||
|
||||
return new AggregationResults<O>(returnPotentiallyMappedResults(outputType, commandResult), commandResult);
|
||||
@@ -1461,61 +1567,60 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
throw new InvalidDataAccessApiUsageException(String.format("Resource %s not found!", function));
|
||||
}
|
||||
|
||||
Scanner scanner = null;
|
||||
|
||||
try {
|
||||
return new Scanner(functionResource.getInputStream()).useDelimiter("\\A").next();
|
||||
scanner = new Scanner(functionResource.getInputStream());
|
||||
return scanner.useDelimiter("\\A").next();
|
||||
} catch (IOException e) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format("Cannot read map-reduce file %s!", function), e);
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
private DBObject copyQuery(Query query, DBObject copyMapReduceOptions) {
|
||||
private void copyMapReduceOptionsToCommand(Query query, MapReduceOptions mapReduceOptions,
|
||||
MapReduceCommand mapReduceCommand) {
|
||||
|
||||
if (query != null) {
|
||||
if (query.getSkip() != 0 || query.getFieldsObject() != null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Can not use skip or field specification with map reduce operations");
|
||||
}
|
||||
if (query.getQueryObject() != null) {
|
||||
copyMapReduceOptions.put("query", queryMapper.getMappedObject(query.getQueryObject(), null));
|
||||
}
|
||||
if (query.getLimit() > 0) {
|
||||
copyMapReduceOptions.put("limit", query.getLimit());
|
||||
if (query.getLimit() > 0 && mapReduceOptions.getLimit() == null) {
|
||||
mapReduceCommand.setLimit(query.getLimit());
|
||||
}
|
||||
if (query.getSortObject() != null) {
|
||||
copyMapReduceOptions.put("sort", queryMapper.getMappedObject(query.getSortObject(), null));
|
||||
mapReduceCommand.setSort(queryMapper.getMappedObject(query.getSortObject(), null));
|
||||
}
|
||||
}
|
||||
return copyMapReduceOptions;
|
||||
}
|
||||
|
||||
private DBObject copyMapReduceOptions(MapReduceOptions mapReduceOptions, MapReduceCommand command) {
|
||||
if (mapReduceOptions.getLimit() != null && mapReduceOptions.getLimit().intValue() > 0) {
|
||||
mapReduceCommand.setLimit(mapReduceOptions.getLimit());
|
||||
}
|
||||
|
||||
if (mapReduceOptions.getJavaScriptMode() != null) {
|
||||
command.addExtraOption("jsMode", true);
|
||||
mapReduceCommand.setJsMode(true);
|
||||
}
|
||||
if (!mapReduceOptions.getExtraOptions().isEmpty()) {
|
||||
for (Map.Entry<String, Object> entry : mapReduceOptions.getExtraOptions().entrySet()) {
|
||||
command.addExtraOption(entry.getKey(), entry.getValue());
|
||||
ReflectiveMapReduceInvoker.addExtraOption(mapReduceCommand, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
if (mapReduceOptions.getFinalizeFunction() != null) {
|
||||
command.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
|
||||
mapReduceCommand.setFinalize(this.replaceWithResourceIfNecessary(mapReduceOptions.getFinalizeFunction()));
|
||||
}
|
||||
if (mapReduceOptions.getOutputDatabase() != null) {
|
||||
command.setOutputDB(mapReduceOptions.getOutputDatabase());
|
||||
mapReduceCommand.setOutputDB(mapReduceOptions.getOutputDatabase());
|
||||
}
|
||||
if (!mapReduceOptions.getScopeVariables().isEmpty()) {
|
||||
command.setScope(mapReduceOptions.getScopeVariables());
|
||||
mapReduceCommand.setScope(mapReduceOptions.getScopeVariables());
|
||||
}
|
||||
|
||||
DBObject commandObject = command.toDBObject();
|
||||
DBObject outObject = (DBObject) commandObject.get("out");
|
||||
|
||||
if (mapReduceOptions.getOutputSharded() != null) {
|
||||
outObject.put("sharded", mapReduceOptions.getOutputSharded());
|
||||
}
|
||||
return commandObject;
|
||||
}
|
||||
|
||||
public Set<String> getCollectionNames() {
|
||||
@@ -1573,8 +1678,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DBObject mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findOne using query: %s fields: %s for class: %s in collection: %s",
|
||||
serializeToJsonSafely(query), mappedFields, entityClass, collectionName));
|
||||
LOGGER.debug("findOne using query: {} fields: {} for class: {} in collection: {}", serializeToJsonSafely(query),
|
||||
mappedFields, entityClass, collectionName);
|
||||
}
|
||||
|
||||
return executeFindOneInternal(new FindOneCallback(mappedQuery, mappedFields), new ReadDbObjectCallback<T>(
|
||||
@@ -1624,8 +1729,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("find using query: %s fields: %s for class: %s in collection: %s",
|
||||
serializeToJsonSafely(mappedQuery), mappedFields, entityClass, collectionName));
|
||||
LOGGER.debug("find using query: {} fields: {} for class: {} in collection: {}",
|
||||
serializeToJsonSafely(mappedQuery), mappedFields, entityClass, collectionName);
|
||||
}
|
||||
|
||||
return executeFindMultiInternal(new FindCallback(mappedQuery, mappedFields), preparer, objectCallback,
|
||||
@@ -1661,12 +1766,16 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
*/
|
||||
protected <T> T doFindAndRemove(String collectionName, DBObject query, DBObject fields, DBObject sort,
|
||||
Class<T> entityClass) {
|
||||
|
||||
EntityReader<? super T, DBObject> readerToUse = this.mongoConverter;
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
|
||||
serializeToJsonSafely(query), fields, sort, entityClass, collectionName));
|
||||
LOGGER.debug("findAndRemove using query: {} fields: {} sort: {} for class: {} in collection: {}",
|
||||
serializeToJsonSafely(query), fields, sort, entityClass, collectionName);
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort),
|
||||
new ReadDbObjectCallback<T>(readerToUse, entityClass), collectionName);
|
||||
}
|
||||
@@ -1688,9 +1797,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
DBObject mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findAndModify using query: %s fields: %s sort: %s for class: %s and update: %s " +
|
||||
"in collection: %s", serializeToJsonSafely(mappedQuery), fields, sort, entityClass,
|
||||
serializeToJsonSafely(mappedUpdate), collectionName));
|
||||
LOGGER.debug(
|
||||
"findAndModify using query: {} fields: {} sort: {} for class: {} and update: {} " + "in collection: {}",
|
||||
serializeToJsonSafely(mappedQuery), fields, sort, entityClass, serializeToJsonSafely(mappedUpdate),
|
||||
collectionName);
|
||||
}
|
||||
|
||||
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
|
||||
@@ -1738,7 +1848,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
prepareCollection(collection);
|
||||
return collection;
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1764,7 +1874,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
collectionName)));
|
||||
return result;
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1817,7 +1927,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1847,7 +1957,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1896,7 +2006,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return;
|
||||
}
|
||||
|
||||
String error = writeResult.getError();
|
||||
String error = ReflectiveWriteResultInvoker.getError(writeResult);
|
||||
|
||||
if (error == null) {
|
||||
return;
|
||||
@@ -1926,18 +2036,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original
|
||||
* exception if the conversation failed. Thus allows safe rethrowing of the return value.
|
||||
*
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex) {
|
||||
RuntimeException resolved = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
return resolved == null ? ex : resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the given {@link CommandResult} for erros and potentially throws an
|
||||
* {@link InvalidDataAccessApiUsageException} for that error.
|
||||
@@ -1976,6 +2074,20 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return queryMapper.getMappedSort(query.getSortObject(), mappingContext.getPersistentEntity(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to convert the given {@link RuntimeException} into a {@link DataAccessException} but returns the original
|
||||
* exception if the conversation failed. Thus allows safe re-throwing of the return value.
|
||||
*
|
||||
* @param ex the exception to translate
|
||||
* @param exceptionTranslator the {@link PersistenceExceptionTranslator} to be used for translation
|
||||
* @return
|
||||
*/
|
||||
private static RuntimeException potentiallyConvertRuntimeException(RuntimeException ex,
|
||||
PersistenceExceptionTranslator exceptionTranslator) {
|
||||
RuntimeException resolved = exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
return resolved == null ? ex : resolved;
|
||||
}
|
||||
|
||||
// Callback implementations
|
||||
|
||||
/**
|
||||
@@ -1998,14 +2110,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
public DBObject doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
if (fields == null) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findOne using query: %s in db.collection: %s",
|
||||
serializeToJsonSafely(query), collection.getFullName()));
|
||||
LOGGER.debug("findOne using query: {} in db.collection: {}", serializeToJsonSafely(query),
|
||||
collection.getFullName());
|
||||
}
|
||||
return collection.findOne(query);
|
||||
} else {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findOne using query: %s fields: %s in db.collection: %s",
|
||||
serializeToJsonSafely(query), fields, collection.getFullName()));
|
||||
LOGGER.debug("findOne using query: {} fields: {} in db.collection: {}", serializeToJsonSafely(query), fields,
|
||||
collection.getFullName());
|
||||
}
|
||||
return collection.findOne(query, fields);
|
||||
}
|
||||
@@ -2093,9 +2205,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
* Simple internal callback to allow operations on a {@link DBObject}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
|
||||
private interface DbObjectCallback<T> {
|
||||
static interface DbObjectCallback<T> {
|
||||
|
||||
T doWith(DBObject object);
|
||||
}
|
||||
@@ -2217,7 +2330,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
throw potentiallyConvertRuntimeException(e, exceptionTranslator);
|
||||
}
|
||||
|
||||
return cursorToUse;
|
||||
@@ -2258,4 +2371,76 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link CloseableIterator} that is backed by a MongoDB {@link Cursor}.
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
static class CloseableIterableCursorAdapter<T> implements CloseableIterator<T> {
|
||||
|
||||
private volatile Cursor cursor;
|
||||
private PersistenceExceptionTranslator exceptionTranslator;
|
||||
private DbObjectCallback<T> objectReadCallback;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CloseableIterableCursorAdapter} backed by the given {@link Cursor}.
|
||||
*
|
||||
* @param cursor
|
||||
* @param exceptionTranslator
|
||||
* @param objectReadCallback
|
||||
*/
|
||||
public CloseableIterableCursorAdapter(Cursor cursor, PersistenceExceptionTranslator exceptionTranslator,
|
||||
DbObjectCallback<T> objectReadCallback) {
|
||||
|
||||
this.cursor = cursor;
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
this.objectReadCallback = objectReadCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
|
||||
if (cursor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return cursor.hasNext();
|
||||
} catch (RuntimeException ex) {
|
||||
throw potentiallyConvertRuntimeException(ex, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
DBObject item = cursor.next();
|
||||
T converted = objectReadCallback.doWith(item);
|
||||
return converted;
|
||||
} catch (RuntimeException ex) {
|
||||
throw potentiallyConvertRuntimeException(ex, exceptionTranslator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
Cursor c = cursor;
|
||||
try {
|
||||
c.close();
|
||||
} catch (RuntimeException ex) {
|
||||
throw potentiallyConvertRuntimeException(ex, exceptionTranslator);
|
||||
} finally {
|
||||
cursor = null;
|
||||
exceptionTranslator = null;
|
||||
objectReadCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveDBCollectionInvoker} provides reflective access to {@link DBCollection} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class ReflectiveDBCollectionInvoker {
|
||||
|
||||
private static final Method GEN_INDEX_NAME_METHOD;
|
||||
private static final Method RESET_INDEX_CHACHE_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", DBObject.class);
|
||||
RESET_INDEX_CHACHE_METHOD = findMethod(DBCollection.class, "resetIndexCache");
|
||||
}
|
||||
|
||||
private ReflectiveDBCollectionInvoker() {}
|
||||
|
||||
/**
|
||||
* Convenience method to generate an index name from the set of fields it is over. Will fall back to a MongoDB Java
|
||||
* driver version 2 compatible way of generating index name in case of {@link MongoClientVersion#isMongo3Driver()}.
|
||||
*
|
||||
* @param keys the names of the fields used in this index
|
||||
* @return
|
||||
*/
|
||||
public static String generateIndexName(DBObject keys) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return genIndexName(keys);
|
||||
}
|
||||
return (String) invokeMethod(GEN_INDEX_NAME_METHOD, null, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of MongoDB Java driver version 2 all indices that have not yet been applied to this collection will be
|
||||
* cleared. Since this method is not available for the MongoDB Java driver version 3 the operation will throw
|
||||
* {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param dbCollection
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static void resetIndexCache(DBCollection dbCollection) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException("The mongo java driver 3 does no loger support resetIndexCache!");
|
||||
}
|
||||
|
||||
invokeMethod(RESET_INDEX_CHACHE_METHOD, dbCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Borrowed from MongoDB Java driver version 2. See <a
|
||||
* href="http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754"
|
||||
* >http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754</a>
|
||||
*
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
private static String genIndexName(DBObject keys) {
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
|
||||
for (String s : keys.keySet()) {
|
||||
|
||||
if (name.length() > 0) {
|
||||
name.append('_');
|
||||
}
|
||||
|
||||
name.append(s).append('_');
|
||||
Object val = keys.get(s);
|
||||
|
||||
if (val instanceof Number || val instanceof String) {
|
||||
name.append(val.toString().replace(' ', '_'));
|
||||
}
|
||||
}
|
||||
|
||||
return name.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveDbInvoker} provides reflective access to {@link DB} API that is not consistently available for
|
||||
* various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveDbInvoker {
|
||||
|
||||
private static final Method DB_IS_AUTHENTICATED_METHOD;
|
||||
private static final Method DB_AUTHENTICATE_METHOD;
|
||||
private static final Method DB_REQUEST_DONE_METHOD;
|
||||
private static final Method DB_ADD_USER_METHOD;
|
||||
private static final Method DB_REQUEST_START_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
DB_IS_AUTHENTICATED_METHOD = findMethod(DB.class, "isAuthenticated");
|
||||
DB_AUTHENTICATE_METHOD = findMethod(DB.class, "authenticate", String.class, char[].class);
|
||||
DB_REQUEST_DONE_METHOD = findMethod(DB.class, "requestDone");
|
||||
DB_ADD_USER_METHOD = findMethod(DB.class, "addUser", String.class, char[].class);
|
||||
DB_REQUEST_START_METHOD = findMethod(DB.class, "requestStart");
|
||||
}
|
||||
|
||||
private ReflectiveDbInvoker() {}
|
||||
|
||||
/**
|
||||
* Authenticate against database using provided credentials in case of a MongoDB Java driver version 2.
|
||||
*
|
||||
* @param mongo must not be {@literal null}.
|
||||
* @param db must not be {@literal null}.
|
||||
* @param credentials must not be {@literal null}.
|
||||
* @param authenticationDatabaseName
|
||||
*/
|
||||
public static void authenticate(Mongo mongo, DB db, UserCredentials credentials, String authenticationDatabaseName) {
|
||||
|
||||
String databaseName = db.getName();
|
||||
|
||||
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
||||
|
||||
synchronized (authDb) {
|
||||
|
||||
Boolean isAuthenticated = (Boolean) invokeMethod(DB_IS_AUTHENTICATED_METHOD, authDb);
|
||||
if (!isAuthenticated) {
|
||||
|
||||
String username = credentials.getUsername();
|
||||
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
||||
|
||||
Boolean authenticated = (Boolean) invokeMethod(DB_AUTHENTICATE_METHOD, authDb, username,
|
||||
password == null ? null : password.toCharArray());
|
||||
if (!authenticated) {
|
||||
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
||||
+ credentials.toString(), databaseName, credentials);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new 'consistent request' in case of MongoDB Java driver version 2. Will do nothing for MongoDB Java driver
|
||||
* version 3 since the operation is no longer available.
|
||||
*
|
||||
* @param db
|
||||
*/
|
||||
public static void requestStart(DB db) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(DB_REQUEST_START_METHOD, db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current 'consistent request'. a new 'consistent request' in case of MongoDB Java driver version 2. Will do
|
||||
* nothing for MongoDB Java driver version 3 since the operation is no longer available
|
||||
*
|
||||
* @param db
|
||||
*/
|
||||
public static void requestDone(DB db) {
|
||||
|
||||
if (MongoClientVersion.isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(DB_REQUEST_DONE_METHOD, db);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param db
|
||||
* @param username
|
||||
* @param password
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static void addUser(DB db, String username, char[] password) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Please use DB.command(…) to call either the createUser or updateUser command!");
|
||||
}
|
||||
|
||||
invokeMethod(DB_ADD_USER_METHOD, db, username, password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.MapReduceCommand;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveMapReduceInvoker} provides reflective access to {@link MapReduceCommand} API that is not
|
||||
* consistently available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveMapReduceInvoker {
|
||||
|
||||
private static final Method ADD_EXTRA_OPTION_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
ADD_EXTRA_OPTION_METHOD = findMethod(MapReduceCommand.class, "addExtraOption", String.class, Object.class);
|
||||
}
|
||||
|
||||
private ReflectiveMapReduceInvoker() {}
|
||||
|
||||
/**
|
||||
* Sets the extra option for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 2.
|
||||
*
|
||||
* @param cmd can be {@literal null} for MongoDB Java driver version 2.
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public static void addExtraOption(MapReduceCommand cmd, String key, Object value) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.notNull(cmd, "MapReduceCommand must not be null!");
|
||||
invokeMethod(ADD_EXTRA_OPTION_METHOD, cmd, key, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.mongodb.MongoOptions;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveMongoOptionsInvoker} provides reflective access to {@link MongoOptions} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ReflectiveMongoOptionsInvoker {
|
||||
|
||||
private static final Method GET_AUTO_CONNECT_RETRY_METHOD;
|
||||
private static final Method SET_AUTO_CONNECT_RETRY_METHOD;
|
||||
private static final Method GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||
private static final Method SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
SET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils
|
||||
.findMethod(MongoOptions.class, "setAutoConnectRetry", boolean.class);
|
||||
GET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils.findMethod(MongoOptions.class, "isAutoConnectRetry");
|
||||
SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||
"setMaxAutoConnectRetryTime", long.class);
|
||||
GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||
"getMaxAutoConnectRetryTime");
|
||||
}
|
||||
|
||||
private ReflectiveMongoOptionsInvoker() {}
|
||||
|
||||
/**
|
||||
* Sets the retry connection flag for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||
* since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param autoConnectRetry
|
||||
*/
|
||||
public static void setAutoConnectRetry(MongoOptions options, boolean autoConnectRetry) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(SET_AUTO_CONNECT_RETRY_METHOD, options, autoConnectRetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java
|
||||
* driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param maxAutoConnectRetryTime
|
||||
*/
|
||||
public static void setMaxAutoConnectRetryTime(MongoOptions options, long maxAutoConnectRetryTime) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options, maxAutoConnectRetryTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the slaveOk attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||
* since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param slaveOk
|
||||
*/
|
||||
public static void setSlaveOk(MongoOptions options, boolean slaveOk) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new DirectFieldAccessor(options).setPropertyValue("slaveOk", slaveOk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the slaveOk attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException} for
|
||||
* MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static boolean getSlaveOk(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Boolean) new DirectFieldAccessor(options).getPropertyValue("slaveOk")).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the autoConnectRetry attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException}
|
||||
* for MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static boolean getAutoConnectRetry(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Boolean) invokeMethod(GET_AUTO_CONNECT_RETRY_METHOD, options)).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Throws
|
||||
* {@link UnsupportedOperationException} for MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static long getMaxAutoConnectRetryTime(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for maxAutoConnectRetryTime which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Long) invokeMethod(GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options)).longValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveWriteConcernInvoker} provides reflective access to {@link WriteConcern} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class ReflectiveWriteConcernInvoker {
|
||||
|
||||
private static final WriteConcern NONE_OR_UNACKNOWLEDGED;
|
||||
|
||||
static {
|
||||
|
||||
NONE_OR_UNACKNOWLEDGED = isMongo3Driver() ? WriteConcern.UNACKNOWLEDGED : (WriteConcern) new DirectFieldAccessor(
|
||||
new WriteConcern()).getPropertyValue("NONE");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link WriteConcern#NONE} for MongoDB Java driver version 2, otherwise {@link WriteConcern#UNACKNOWLEDGED}.
|
||||
*/
|
||||
public static WriteConcern noneOrUnacknowledged() {
|
||||
return NONE_OR_UNACKNOWLEDGED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.WriteResult;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveWriteResultInvoker} provides reflective access to {@link WriteResult} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveWriteResultInvoker {
|
||||
|
||||
private static final Method GET_ERROR_METHOD;
|
||||
private static final Method WAS_ACKNOWLEDGED_METHOD;
|
||||
|
||||
private ReflectiveWriteResultInvoker() {}
|
||||
|
||||
static {
|
||||
|
||||
GET_ERROR_METHOD = findMethod(WriteResult.class, "getError");
|
||||
WAS_ACKNOWLEDGED_METHOD = findMethod(WriteResult.class, "wasAcknowledged");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param writeResult can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return null in case of MongoDB Java driver version 3 since errors are thrown as {@link MongoException}.
|
||||
*/
|
||||
public static String getError(WriteResult writeResult) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (String) invokeMethod(GET_ERROR_METHOD, writeResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param writeResult
|
||||
* @return return in case of MongoDB Java driver version 2.
|
||||
*/
|
||||
public static boolean wasAcknowledged(WriteResult writeResult) {
|
||||
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD, writeResult)).booleanValue() : true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
|
||||
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||
|
||||
import com.mongodb.DB;
|
||||
|
||||
/**
|
||||
* Script operations on {@link com.mongodb.DB} level. Allows interaction with server side JavaScript functions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface ScriptOperations {
|
||||
|
||||
/**
|
||||
* Store given {@link ExecutableMongoScript} generating a syntheitcal name so that it can be called by it
|
||||
* subsequently.
|
||||
*
|
||||
* @param script must not be {@literal null}.
|
||||
* @return {@link NamedMongoScript} with name under which the {@code JavaScript} function can be called.
|
||||
*/
|
||||
NamedMongoScript register(ExecutableMongoScript script);
|
||||
|
||||
/**
|
||||
* Registers the given {@link NamedMongoScript} in the database.
|
||||
*
|
||||
* @param script the {@link NamedMongoScript} to be registered.
|
||||
* @return
|
||||
*/
|
||||
NamedMongoScript register(NamedMongoScript script);
|
||||
|
||||
/**
|
||||
* Executes the {@literal script} by either calling it via its {@literal name} or directly sending it.
|
||||
*
|
||||
* @param script must not be {@literal null}.
|
||||
* @param args arguments to pass on for script execution.
|
||||
* @return the script evaluation result.
|
||||
* @throws org.springframework.dao.DataAccessException
|
||||
*/
|
||||
Object execute(ExecutableMongoScript script, Object... args);
|
||||
|
||||
/**
|
||||
* Call the {@literal JavaScript} by its name.
|
||||
*
|
||||
* @param scriptName must not be {@literal null} or empty.
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
Object call(String scriptName, Object... args);
|
||||
|
||||
/**
|
||||
* Checks {@link DB} for existence of {@link ServerSideJavaScript} with given name.
|
||||
*
|
||||
* @param scriptName must not be {@literal null} or empty.
|
||||
* @return false if no {@link ServerSideJavaScript} with given name exists.
|
||||
*/
|
||||
boolean exists(String scriptName);
|
||||
|
||||
/**
|
||||
* Returns names of {@literal JavaScript} functions that can be called.
|
||||
*
|
||||
* @return empty {@link Set} if no scripts found.
|
||||
*/
|
||||
Set<String> getScriptNames();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -19,6 +19,7 @@ import java.net.UnknownHostException;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
@@ -27,6 +28,8 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.MongoURI;
|
||||
import com.mongodb.WriteConcern;
|
||||
@@ -37,6 +40,7 @@ import com.mongodb.WriteConcern;
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
|
||||
@@ -54,7 +58,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
*
|
||||
* @param mongo Mongo instance, must not be {@literal null}.
|
||||
* @param databaseName database name, not be {@literal null} or empty.
|
||||
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClient, String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
||||
this(mongo, databaseName, null);
|
||||
}
|
||||
@@ -65,7 +71,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
* @param mongo Mongo instance, must not be {@literal null}.
|
||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||
* @param credentials username and password.
|
||||
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||
this(mongo, databaseName, credentials, false, null);
|
||||
}
|
||||
@@ -77,7 +85,9 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||
* @param credentials username and password.
|
||||
* @param authenticationDatabaseName the database name to use for authentication
|
||||
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
String authenticationDatabaseName) {
|
||||
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
|
||||
@@ -90,16 +100,44 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
* @throws MongoException
|
||||
* @throws UnknownHostException
|
||||
* @see MongoURI
|
||||
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClientURI)} instead.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
|
||||
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
|
||||
true, uri.getDatabase());
|
||||
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())), true,
|
||||
uri.getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
|
||||
*
|
||||
* @param uri must not be {@literal null}.
|
||||
* @throws UnknownHostException
|
||||
* @since 1.7
|
||||
*/
|
||||
public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
|
||||
this(new MongoClient(uri), uri.getDatabase(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClient}.
|
||||
*
|
||||
* @param mongoClient must not be {@literal null}.
|
||||
* @param databaseName must not be {@literal null}.
|
||||
* @since 1.7
|
||||
*/
|
||||
public SimpleMongoDbFactory(MongoClient mongoClient, String databaseName) {
|
||||
this(mongoClient, databaseName, false);
|
||||
}
|
||||
|
||||
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
boolean mongoInstanceCreated, String authenticationDatabaseName) {
|
||||
|
||||
if (mongo instanceof MongoClient && (credentials != null && !UserCredentials.NO_CREDENTIALS.equals(credentials))) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Usage of 'UserCredentials' with 'MongoClient' is no longer supported. Please use 'MongoCredential' for 'MongoClient' or just 'Mongo'.");
|
||||
}
|
||||
|
||||
Assert.notNull(mongo, "Mongo must not be null");
|
||||
Assert.hasText(databaseName, "Database name must not be empty");
|
||||
Assert.isTrue(databaseName.matches("[\\w-]+"),
|
||||
@@ -117,6 +155,25 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
"Authentication database name must only contain letters, numbers, underscores and dashes!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @param databaseName
|
||||
* @param mongoInstanceCreated
|
||||
* @since 1.7
|
||||
*/
|
||||
private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
|
||||
|
||||
Assert.notNull(client, "MongoClient must not be null!");
|
||||
Assert.hasText(databaseName, "Database name must not be empty!");
|
||||
|
||||
this.mongo = client;
|
||||
this.databaseName = databaseName;
|
||||
this.mongoInstanceCreated = mongoInstanceCreated;
|
||||
this.exceptionTranslator = new MongoExceptionTranslator();
|
||||
this.credentials = UserCredentials.NO_CREDENTIALS;
|
||||
this.authenticationDatabaseName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.
|
||||
*
|
||||
@@ -138,6 +195,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.MongoDbFactory#getDb(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public DB getDb(String dbName) throws DataAccessException {
|
||||
|
||||
Assert.hasText(dbName, "Database name must not be empty.");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedFi
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -152,7 +153,7 @@ public class Aggregation {
|
||||
protected Aggregation(List<AggregationOperation> aggregationOperations, AggregationOptions options) {
|
||||
|
||||
Assert.notNull(aggregationOperations, "AggregationOperations must not be null!");
|
||||
Assert.isTrue(aggregationOperations.size() > 0, "At least one AggregationOperation has to be provided");
|
||||
Assert.isTrue(!aggregationOperations.isEmpty(), "At least one AggregationOperation has to be provided");
|
||||
Assert.notNull(options, "AggregationOptions must not be null!");
|
||||
|
||||
this.operations = aggregationOperations;
|
||||
@@ -291,6 +292,19 @@ public class Aggregation {
|
||||
return Fields.from(field(name, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoNearOperation} instance from the given {@link NearQuery} and the{@code distanceField}. The
|
||||
* {@code distanceField} defines output field that contains the calculated distance.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param distanceField must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public static GeoNearOperation geoNear(NearQuery query, String distanceField) {
|
||||
return new GeoNearOperation(query, distanceField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link AggregationOptions.Builder}.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* An {@link AggregationExpression} can be used with field expressions in aggregation pipeline stages like
|
||||
* {@code project} and {@code group}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface AggregationExpression {
|
||||
|
||||
/**
|
||||
* Turns the {@link AggregationExpression} into a {@link DBObject} within the given
|
||||
* {@link AggregationOperationContext}.
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
DBObject toDbObject(AggregationOperationContext context);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* An enum of supported {@link AggregationExpression}s in aggregation pipeline stages.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
*/
|
||||
public enum AggregationFunctionExpressions {
|
||||
|
||||
SIZE;
|
||||
|
||||
/**
|
||||
* Returns an {@link AggregationExpression} build from the current {@link Enum} name and the given parameters.
|
||||
*
|
||||
* @param parameters must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public AggregationExpression of(Object... parameters) {
|
||||
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
return new FunctionExpression(name().toLowerCase(), parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AggregationExpression} representing a function call.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
*/
|
||||
static class FunctionExpression implements AggregationExpression {
|
||||
|
||||
private final String name;
|
||||
private final List<Object> values;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionExpression} for the given name and values.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param values must not be {@literal null}.
|
||||
*/
|
||||
public FunctionExpression(String name, Object[] values) {
|
||||
|
||||
Assert.hasText(name, "Name must not be null!");
|
||||
Assert.notNull(values, "Values must not be null!");
|
||||
|
||||
this.name = name;
|
||||
this.values = Arrays.asList(values);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.Expression#toDbObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public DBObject toDbObject(AggregationOperationContext context) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>(values.size());
|
||||
|
||||
for (Object value : values) {
|
||||
args.add(unpack(value, context));
|
||||
}
|
||||
|
||||
return new BasicDBObject("$" + name, args);
|
||||
}
|
||||
|
||||
private static Object unpack(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDbObject(context);
|
||||
}
|
||||
|
||||
if (value instanceof Field) {
|
||||
return context.getReference((Field) value).toString();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExposedFields} instance for the given fields in either sythetic or non-synthetic way.
|
||||
* Creates a new {@link ExposedFields} instance for the given fields in either synthetic or non-synthetic way.
|
||||
*
|
||||
* @param fields must not be {@literal null}.
|
||||
* @param synthetic
|
||||
@@ -107,7 +107,7 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExposedFields} with the given orignals and synthetics.
|
||||
* Creates a new {@link ExposedFields} with the given originals and synthetics.
|
||||
*
|
||||
* @param originals must not be {@literal null}.
|
||||
* @param synthetic must not be {@literal null}.
|
||||
@@ -363,7 +363,7 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the referenve value for the given field reference. Will return 1 for a synthetic, unaliased field or the
|
||||
* Returns the reference value for the given field reference. Will return 1 for a synthetic, unaliased field or the
|
||||
* raw rendering of the reference otherwise.
|
||||
*
|
||||
* @return
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -84,6 +84,15 @@ public final class Fields implements Iterable<Field> {
|
||||
return new AggregationField(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Field} with the given {@code name} and {@code target}.
|
||||
* <p>
|
||||
* The {@code target} is the name of the backing document field that will be aliased with {@code name}.
|
||||
*
|
||||
* @param name
|
||||
* @param target must not be {@literal null} or empty
|
||||
* @return
|
||||
*/
|
||||
public static Field field(String name, String target) {
|
||||
Assert.hasText(target, "Target must not be null or empty!");
|
||||
return new AggregationField(name, target);
|
||||
@@ -187,15 +196,24 @@ public final class Fields implements Iterable<Field> {
|
||||
private final String target;
|
||||
|
||||
/**
|
||||
* Creates an aggregation field with the given name. As no target is set explicitly, the name will be used as target
|
||||
* as well.
|
||||
* Creates an aggregation field with the given {@code name}.
|
||||
*
|
||||
* @param key
|
||||
* @see AggregationField#AggregationField(String, String).
|
||||
* @param name must not be {@literal null} or empty
|
||||
*/
|
||||
public AggregationField(String key) {
|
||||
this(key, null);
|
||||
public AggregationField(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an aggregation field with the given {@code name} and {@code target}.
|
||||
* <p>
|
||||
* The {@code name} serves as an alias for the actual backing document field denoted by {@code target}. If no target
|
||||
* is set explicitly, the name will be used as target.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty
|
||||
* @param target
|
||||
*/
|
||||
public AggregationField(String name, String target) {
|
||||
|
||||
String nameToSet = cleanUp(name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -22,17 +22,33 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Represents a {@code geoNear} aggregation operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#geoNear(NearQuery, String)} instead of creating
|
||||
* instances of this class directly.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.3
|
||||
*/
|
||||
public class GeoNearOperation implements AggregationOperation {
|
||||
|
||||
private final NearQuery nearQuery;
|
||||
private final String distanceField;
|
||||
|
||||
public GeoNearOperation(NearQuery nearQuery) {
|
||||
/**
|
||||
* Creates a new {@link GeoNearOperation} from the given {@link NearQuery} and the given distance field. The
|
||||
* {@code distanceField} defines output field that contains the calculated distance.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param distanceField must not be {@literal null}.
|
||||
*/
|
||||
public GeoNearOperation(NearQuery nearQuery, String distanceField) {
|
||||
|
||||
Assert.notNull(nearQuery, "NearQuery must not be null.");
|
||||
Assert.hasLength(distanceField, "Distance field must not be null or empty.");
|
||||
|
||||
Assert.notNull(nearQuery);
|
||||
this.nearQuery = nearQuery;
|
||||
this.distanceField = distanceField;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -41,6 +57,10 @@ public class GeoNearOperation implements AggregationOperation {
|
||||
*/
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
return new BasicDBObject("$geoNear", context.getMappedObject(nearQuery.toDBObject()));
|
||||
|
||||
BasicDBObject command = (BasicDBObject) context.getMappedObject(nearQuery.toDBObject());
|
||||
command.put("distanceField", distanceField);
|
||||
|
||||
return new BasicDBObject("$geoNear", command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -31,6 +31,9 @@ import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $group}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#group(Fields)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/group/#stage._S_group
|
||||
* @author Sebastian Herold
|
||||
@@ -190,6 +193,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.LAST, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $last}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder last(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.LAST, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given field-reference.
|
||||
*
|
||||
@@ -200,6 +213,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.FIRST, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder first(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.FIRST, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given field-reference.
|
||||
*
|
||||
@@ -210,6 +233,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.AVG, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder avg(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.AVG, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $push}-expression for the given field-reference.
|
||||
*
|
||||
@@ -244,6 +277,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.MIN, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $min}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder min(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.MIN, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given field-reference.
|
||||
*
|
||||
@@ -254,6 +297,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.MAX, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder max(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.MAX, null, expr);
|
||||
}
|
||||
|
||||
private GroupOperationBuilder newBuilder(Keyword keyword, String reference, Object value) {
|
||||
return new GroupOperationBuilder(this, new Operation(keyword, null, reference, value));
|
||||
}
|
||||
@@ -366,6 +419,11 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
public Object getValue(AggregationOperationContext context) {
|
||||
|
||||
if (reference == null) {
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDbObject(context);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -21,7 +21,10 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the {@code $limit}-operation
|
||||
* Encapsulates the {@code $limit}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#limit(long)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/limit/
|
||||
* @author Thomas Darimont
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -22,7 +22,11 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the {@code $match}-operation
|
||||
* Encapsulates the {@code $match}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method
|
||||
* {@link Aggregation#match(org.springframework.data.mongodb.core.query.Criteria)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/match/
|
||||
* @author Sebastian Herold
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -21,6 +21,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -28,15 +29,19 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $project}-operation. Projection of field to be used in an
|
||||
* {@link Aggregation}. A projection is similar to a {@link Field} inclusion/exclusion but more powerful. It can
|
||||
* generate new fields, change values of given field etc.
|
||||
* Encapsulates the aggregation framework {@code $project}-operation.
|
||||
* <p>
|
||||
* Projection of field to be used in an {@link Aggregation}. A projection is similar to a {@link Field}
|
||||
* inclusion/exclusion but more powerful. It can generate new fields, change values of given field etc.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#project(Fields)} instead of creating instances of
|
||||
* this class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/project/
|
||||
* @author Tobias Trelle
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.3
|
||||
*/
|
||||
public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
@@ -118,6 +123,10 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return new ExpressionProjectionOperationBuilder(expression, this, params);
|
||||
}
|
||||
|
||||
public ProjectionOperationBuilder and(AggregationExpression expression) {
|
||||
return new ProjectionOperationBuilder(expression, this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes the given fields from the projection.
|
||||
*
|
||||
@@ -417,9 +426,13 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
if (this.previousProjection != null) {
|
||||
return this.operation.andReplaceLastOneWith(this.previousProjection.withAlias(alias));
|
||||
} else {
|
||||
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
||||
}
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return this.operation.and(new ExpressionProjection(Fields.field(alias), (AggregationExpression) value));
|
||||
}
|
||||
|
||||
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,6 +562,10 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return project("mod", Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
public ProjectionOperationBuilder size() {
|
||||
return project("size");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
@@ -748,6 +765,20 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return field;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#getExposedField()
|
||||
*/
|
||||
@Override
|
||||
public ExposedField getExposedField() {
|
||||
|
||||
if (!getField().isAliased()) {
|
||||
return super.getExposedField();
|
||||
}
|
||||
|
||||
return new ExposedField(new AggregationField(getField().getName()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link OperationProjection} with the given alias.
|
||||
*
|
||||
@@ -937,4 +968,31 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
*/
|
||||
public abstract DBObject toDBObject(AggregationOperationContext context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
static class ExpressionProjection extends Projection {
|
||||
|
||||
private final AggregationExpression expression;
|
||||
private final Field field;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionProjection}.
|
||||
*
|
||||
* @param field
|
||||
* @param expression
|
||||
*/
|
||||
public ExpressionProjection(Field field, AggregationExpression expression) {
|
||||
|
||||
super(field);
|
||||
this.field = field;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
return new BasicDBObject(field.getName(), expression.toDbObject(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -22,6 +22,9 @@ import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $skip}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#skip(int)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/skip/
|
||||
* @author Thomas Darimont
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -26,6 +26,9 @@ import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $sort}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#sort(Direction, String...)} instead of creating
|
||||
* instances of this class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/sort/#pipe._S_sort
|
||||
* @author Thomas Darimont
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,9 @@ import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $unwind}-operation.
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#unwind(String)} instead of creating instances of
|
||||
* this class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/unwind/#pipe._S_unwind
|
||||
* @author Thomas Darimont
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -20,7 +20,7 @@ import java.math.BigInteger;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.convert.EntityInstantiators;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToObjectIdConverter;
|
||||
@@ -46,10 +46,8 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
|
||||
*
|
||||
* @param conversionService
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public AbstractMongoConverter(GenericConversionService conversionService) {
|
||||
this.conversionService = conversionService == null ? ConversionServiceFactory.createDefaultConversionService()
|
||||
: conversionService;
|
||||
this.conversionService = conversionService == null ? new DefaultConversionService() : conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,15 +75,13 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
|
||||
*/
|
||||
private void initializeConverters() {
|
||||
|
||||
if (!conversionService.canConvert(ObjectId.class, String.class)) {
|
||||
conversionService.addConverter(ObjectIdToStringConverter.INSTANCE);
|
||||
}
|
||||
if (!conversionService.canConvert(String.class, ObjectId.class)) {
|
||||
conversionService.addConverter(StringToObjectIdConverter.INSTANCE);
|
||||
}
|
||||
conversionService.addConverter(ObjectIdToStringConverter.INSTANCE);
|
||||
conversionService.addConverter(StringToObjectIdConverter.INSTANCE);
|
||||
|
||||
if (!conversionService.canConvert(ObjectId.class, BigInteger.class)) {
|
||||
conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE);
|
||||
}
|
||||
|
||||
if (!conversionService.canConvert(BigInteger.class, ObjectId.class)) {
|
||||
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -17,14 +17,15 @@ package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -38,17 +39,21 @@ import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.convert.JodaTimeConverters;
|
||||
import org.springframework.data.convert.Jsr310Converters;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.ThreeTenBackPortConverters;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.BigIntegerToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToNamedMongoScriptCoverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.NamedMongoScriptToDBObjectConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigIntegerConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.StringToURLConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.TermToStringConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverters.URLToStringConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
import org.springframework.data.util.CacheValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -72,10 +77,13 @@ public class CustomConversions {
|
||||
private final Set<ConvertiblePair> writingPairs;
|
||||
private final Set<Class<?>> customSimpleTypes;
|
||||
private final SimpleTypeHolder simpleTypeHolder;
|
||||
private final ConcurrentMap<ConvertiblePair, CacheValue> customReadTargetTypes;
|
||||
|
||||
private final List<Object> converters;
|
||||
|
||||
private final Map<ConvertiblePair, CacheValue<Class<?>>> customReadTargetTypes;
|
||||
private final Map<ConvertiblePair, CacheValue<Class<?>>> customWriteTargetTypes;
|
||||
private final Map<Class<?>, CacheValue<Class<?>>> rawWriteTargetTypes;
|
||||
|
||||
/**
|
||||
* Creates an empty {@link CustomConversions} object.
|
||||
*/
|
||||
@@ -95,7 +103,9 @@ public class CustomConversions {
|
||||
this.readingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||
this.writingPairs = new LinkedHashSet<ConvertiblePair>();
|
||||
this.customSimpleTypes = new HashSet<Class<?>>();
|
||||
this.customReadTargetTypes = new ConcurrentHashMap<GenericConverter.ConvertiblePair, CacheValue>();
|
||||
this.customReadTargetTypes = new ConcurrentHashMap<ConvertiblePair, CacheValue<Class<?>>>();
|
||||
this.customWriteTargetTypes = new ConcurrentHashMap<ConvertiblePair, CacheValue<Class<?>>>();
|
||||
this.rawWriteTargetTypes = new ConcurrentHashMap<Class<?>, CacheValue<Class<?>>>();
|
||||
|
||||
List<Object> toRegister = new ArrayList<Object>();
|
||||
|
||||
@@ -110,10 +120,13 @@ public class CustomConversions {
|
||||
toRegister.add(StringToURLConverter.INSTANCE);
|
||||
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
||||
toRegister.add(TermToStringConverter.INSTANCE);
|
||||
toRegister.add(NamedMongoScriptToDBObjectConverter.INSTANCE);
|
||||
toRegister.add(DBObjectToNamedMongoScriptCoverter.INSTANCE);
|
||||
|
||||
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
||||
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
||||
toRegister.addAll(Jsr310Converters.getConvertersToRegister());
|
||||
toRegister.addAll(ThreeTenBackPortConverters.getConvertersToRegister());
|
||||
|
||||
for (Object c : toRegister) {
|
||||
registerConversion(c);
|
||||
@@ -179,8 +192,8 @@ public class CustomConversions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a conversion for the given converter. Inspects either generics or the {@link ConvertiblePair}s returned
|
||||
* by a {@link GenericConverter}.
|
||||
* Registers a conversion for the given converter. Inspects either generics of {@link Converter} and
|
||||
* {@link ConverterFactory} or the {@link ConvertiblePair}s returned by a {@link GenericConverter}.
|
||||
*
|
||||
* @param converter
|
||||
*/
|
||||
@@ -195,6 +208,10 @@ public class CustomConversions {
|
||||
for (ConvertiblePair pair : genericConverter.getConvertibleTypes()) {
|
||||
register(new ConverterRegistration(pair, isReading, isWriting));
|
||||
}
|
||||
} else if (converter instanceof ConverterFactory) {
|
||||
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), ConverterFactory.class);
|
||||
register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting));
|
||||
} else if (converter instanceof Converter) {
|
||||
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
|
||||
register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting));
|
||||
@@ -240,70 +257,103 @@ public class CustomConversions {
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getCustomWriteTarget(Class<?> sourceType) {
|
||||
return getCustomWriteTarget(sourceType, null);
|
||||
public Class<?> getCustomWriteTarget(final Class<?> sourceType) {
|
||||
|
||||
return getOrCreateAndCache(sourceType, rawWriteTargetTypes, new Producer() {
|
||||
|
||||
@Override
|
||||
public Class<?> get() {
|
||||
return getCustomTarget(sourceType, null, writingPairs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target type we can write an onject of the given source type to. The returned type might be a subclass
|
||||
* oth the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply return the
|
||||
* first target type matching or {@literal null} if no conversion can be found.
|
||||
* Returns the target type we can readTargetWriteLocl an inject of the given source type to. The returned type might
|
||||
* be a subclass of the given expected type though. If {@code expectedTargetType} is {@literal null} we will simply
|
||||
* return the first target type matching or {@literal null} if no conversion can be found.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @param requestedTargetType
|
||||
* @return
|
||||
*/
|
||||
public Class<?> getCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||
public Class<?> getCustomWriteTarget(final Class<?> sourceType, final Class<?> requestedTargetType) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
if (requestedTargetType == null) {
|
||||
return getCustomWriteTarget(sourceType);
|
||||
}
|
||||
|
||||
return getCustomTarget(sourceType, requestedTargetType, writingPairs);
|
||||
return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customWriteTargetTypes,
|
||||
new Producer() {
|
||||
|
||||
@Override
|
||||
public Class<?> get() {
|
||||
return getCustomTarget(sourceType, requestedTargetType, writingPairs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to write into a Mongo native type. The returned type might
|
||||
* be a subclass of the given expected type though.
|
||||
* Returns whether we have a custom conversion registered to readTargetWriteLocl into a Mongo native type. The
|
||||
* returned type might be a subclass of the given expected type though.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public boolean hasCustomWriteTarget(Class<?> sourceType) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
return hasCustomWriteTarget(sourceType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to write an object of the given source type into an object
|
||||
* of the given Mongo native target type.
|
||||
* Returns whether we have a custom conversion registered to readTargetWriteLocl an object of the given source type
|
||||
* into an object of the given Mongo native target type.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param requestedTargetType
|
||||
* @return
|
||||
*/
|
||||
public boolean hasCustomWriteTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
return getCustomWriteTarget(sourceType, requestedTargetType) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we have a custom conversion registered to read the given source into the given target type.
|
||||
* Returns whether we have a custom conversion registered to readTargetReadLock the given source into the given target
|
||||
* type.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}
|
||||
* @param requestedTargetType must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public boolean hasCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
Assert.notNull(requestedTargetType);
|
||||
|
||||
return getCustomReadTarget(sourceType, requestedTargetType) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
|
||||
* Returns the actual target type for the given {@code sourceType} and {@code requestedTargetType}. Note that the
|
||||
* returned {@link Class} could be an assignable type to the given {@code requestedTargetType}.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param requestedTargetType can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getCustomReadTarget(final Class<?> sourceType, final Class<?> requestedTargetType) {
|
||||
|
||||
if (requestedTargetType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getOrCreateAndCache(new ConvertiblePair(sourceType, requestedTargetType), customReadTargetTypes,
|
||||
new Producer() {
|
||||
|
||||
@Override
|
||||
public Class<?> get() {
|
||||
return getCustomTarget(sourceType, requestedTargetType, readingPairs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the given {@link ConvertiblePair}s for ones that have a source compatible type as source. Additionally
|
||||
* checks assignability of the target type if one is given.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
@@ -312,11 +362,15 @@ public class CustomConversions {
|
||||
* @return
|
||||
*/
|
||||
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
|
||||
Iterable<ConvertiblePair> pairs) {
|
||||
Collection<ConvertiblePair> pairs) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
Assert.notNull(pairs);
|
||||
|
||||
if (requestedTargetType != null && pairs.contains(new ConvertiblePair(sourceType, requestedTargetType))) {
|
||||
return requestedTargetType;
|
||||
}
|
||||
|
||||
for (ConvertiblePair typePair : pairs) {
|
||||
if (typePair.getSourceType().isAssignableFrom(sourceType)) {
|
||||
Class<?> targetType = typePair.getTargetType();
|
||||
@@ -330,32 +384,31 @@ public class CustomConversions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual target type for the given {@code sourceType} and {@code requestedTargetType}. Note that the
|
||||
* returned {@link Class} could be an assignable type to the given {@code requestedTargetType}.
|
||||
* Will try to find a value for the given key in the given cache or produce one using the given {@link Producer} and
|
||||
* store it in the cache.
|
||||
*
|
||||
* @param sourceType must not be {@literal null}.
|
||||
* @param requestedTargetType can be {@literal null}.
|
||||
* @param key the key to lookup a potentially existing value, must not be {@literal null}.
|
||||
* @param cache the cache to find the value in, must not be {@literal null}.
|
||||
* @param producer the {@link Producer} to create values to cache, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getCustomReadTarget(Class<?> sourceType, Class<?> requestedTargetType) {
|
||||
private static <T> Class<?> getOrCreateAndCache(T key, Map<T, CacheValue<Class<?>>> cache, Producer producer) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
CacheValue<Class<?>> cacheValue = cache.get(key);
|
||||
|
||||
if (requestedTargetType == null) {
|
||||
return null;
|
||||
if (cacheValue != null) {
|
||||
return cacheValue.getValue();
|
||||
}
|
||||
|
||||
ConvertiblePair lookupKey = new ConvertiblePair(sourceType, requestedTargetType);
|
||||
CacheValue readTargetTypeValue = customReadTargetTypes.get(lookupKey);
|
||||
Class<?> type = producer.get();
|
||||
cache.put(key, CacheValue.<Class<?>> ofNullable(type));
|
||||
|
||||
if (readTargetTypeValue != null) {
|
||||
return readTargetTypeValue.getType();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
readTargetTypeValue = CacheValue.of(getCustomTarget(sourceType, requestedTargetType, readingPairs));
|
||||
CacheValue cacheValue = customReadTargetTypes.putIfAbsent(lookupKey, readTargetTypeValue);
|
||||
private interface Producer {
|
||||
|
||||
return cacheValue != null ? cacheValue.getType() : readTargetTypeValue.getType();
|
||||
Class<?> get();
|
||||
}
|
||||
|
||||
@WritingConverter
|
||||
@@ -375,30 +428,4 @@ public class CustomConversions {
|
||||
return source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to safely store {@literal null} values in the type cache.
|
||||
*
|
||||
* @author Patryk Wasik
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
private static class CacheValue {
|
||||
|
||||
private static final CacheValue ABSENT = new CacheValue(null);
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
public CacheValue(Class<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
static CacheValue of(Class<?> type) {
|
||||
return type == null ? ABSENT : new CacheValue(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -34,7 +34,7 @@ import com.mongodb.DBObject;
|
||||
*/
|
||||
class DBObjectAccessor {
|
||||
|
||||
private final DBObject dbObject;
|
||||
private final BasicDBObject dbObject;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DBObjectAccessor} for the given {@link DBObject}.
|
||||
@@ -46,7 +46,7 @@ class DBObjectAccessor {
|
||||
Assert.notNull(dbObject, "DBObject must not be null!");
|
||||
Assert.isInstanceOf(BasicDBObject.class, dbObject, "Given DBObject must be a BasicDBObject!");
|
||||
|
||||
this.dbObject = dbObject;
|
||||
this.dbObject = (BasicDBObject) dbObject;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,6 +62,11 @@ class DBObjectAccessor {
|
||||
Assert.notNull(prop, "MongoPersistentProperty must not be null!");
|
||||
String fieldName = prop.getFieldName();
|
||||
|
||||
if (!fieldName.contains(".")) {
|
||||
dbObject.put(fieldName, value);
|
||||
return;
|
||||
}
|
||||
|
||||
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||
DBObject dbObject = this.dbObject;
|
||||
|
||||
@@ -70,9 +75,7 @@ class DBObjectAccessor {
|
||||
String part = parts.next();
|
||||
|
||||
if (parts.hasNext()) {
|
||||
BasicDBObject nestedDbObject = new BasicDBObject();
|
||||
dbObject.put(part, nestedDbObject);
|
||||
dbObject = nestedDbObject;
|
||||
dbObject = getOrCreateNestedDbObject(part, dbObject);
|
||||
} else {
|
||||
dbObject.put(part, value);
|
||||
}
|
||||
@@ -87,12 +90,16 @@ class DBObjectAccessor {
|
||||
* @param property must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object get(MongoPersistentProperty property) {
|
||||
|
||||
String fieldName = property.getFieldName();
|
||||
|
||||
if (!fieldName.contains(".")) {
|
||||
return this.dbObject.get(fieldName);
|
||||
}
|
||||
|
||||
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
|
||||
Map<Object, Object> source = this.dbObject.toMap();
|
||||
Map<String, Object> source = this.dbObject;
|
||||
Object result = null;
|
||||
|
||||
while (source != null && parts.hasNext()) {
|
||||
@@ -107,17 +114,45 @@ class DBObjectAccessor {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given source object as map, i.e. {@link BasicDBObject}s and maps as is or {@literal null} otherwise.
|
||||
*
|
||||
* @param source can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Object, Object> getAsMap(Object source) {
|
||||
private static Map<String, Object> getAsMap(Object source) {
|
||||
|
||||
if (source instanceof BasicDBObject) {
|
||||
return ((DBObject) source).toMap();
|
||||
return (BasicDBObject) source;
|
||||
}
|
||||
|
||||
if (source instanceof Map) {
|
||||
return (Map<Object, Object>) source;
|
||||
return (Map<String, Object>) source;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DBObject} which either already exists in the given source under the given key, or creates a new
|
||||
* nested one, registers it with the source and returns it.
|
||||
*
|
||||
* @param key must not be {@literal null} or empty.
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static DBObject getOrCreateNestedDbObject(String key, DBObject source) {
|
||||
|
||||
Object existing = source.get(key);
|
||||
|
||||
if (existing instanceof BasicDBObject) {
|
||||
return (BasicDBObject) existing;
|
||||
}
|
||||
|
||||
DBObject nested = new BasicDBObject();
|
||||
source.put(key, nested);
|
||||
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.mongodb.core.convert;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,7 @@ import com.mongodb.DBRef;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.4
|
||||
*/
|
||||
public interface DbRefResolver {
|
||||
@@ -53,4 +55,13 @@ public interface DbRefResolver {
|
||||
*/
|
||||
DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation, MongoPersistentEntity<?> entity,
|
||||
Object id);
|
||||
|
||||
/**
|
||||
* Actually loads the {@link DBRef} from the datasource.
|
||||
*
|
||||
* @param dbRef must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
DBObject fetch(DBRef dbRef);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 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.
|
||||
@@ -39,9 +39,8 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.objenesis.ObjenesisStd;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
@@ -50,6 +49,7 @@ import com.mongodb.DBRef;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.4
|
||||
*/
|
||||
public class DefaultDbRefResolver implements DbRefResolver {
|
||||
@@ -97,11 +97,16 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
@Override
|
||||
public DBRef createDbRef(org.springframework.data.mongodb.core.mapping.DBRef annotation,
|
||||
MongoPersistentEntity<?> entity, Object id) {
|
||||
return new DBRef(entity.getCollection(), id);
|
||||
}
|
||||
|
||||
DB db = mongoDbFactory.getDb();
|
||||
db = annotation != null && StringUtils.hasText(annotation.db()) ? mongoDbFactory.getDb(annotation.db()) : db;
|
||||
|
||||
return new DBRef(db, entity.getCollection(), id);
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#fetch(com.mongodb.DBRef)
|
||||
*/
|
||||
@Override
|
||||
public DBObject fetch(DBRef dbRef) {
|
||||
return ReflectiveDBRefResolver.fetch(mongoDbFactory, dbRef);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,7 +287,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
|
||||
StringBuilder description = new StringBuilder();
|
||||
if (dbref != null) {
|
||||
description.append(dbref.getRef());
|
||||
description.append(dbref.getCollectionName());
|
||||
description.append(":");
|
||||
description.append(dbref.getId());
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -30,9 +30,18 @@ import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJson;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonGeometryCollection;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonMultiLineString;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.data.mongodb.core.query.GeoCommand;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -43,6 +52,7 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
abstract class GeoConverters {
|
||||
@@ -57,6 +67,7 @@ abstract class GeoConverters {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Collection<? extends Object> getConvertersToRegister() {
|
||||
return Arrays.asList( //
|
||||
BoxToDbObjectConverter.INSTANCE //
|
||||
@@ -69,7 +80,17 @@ abstract class GeoConverters {
|
||||
, DbObjectToSphereConverter.INSTANCE //
|
||||
, DbObjectToPointConverter.INSTANCE //
|
||||
, PointToDbObjectConverter.INSTANCE //
|
||||
, GeoCommandToDbObjectConverter.INSTANCE);
|
||||
, GeoCommandToDbObjectConverter.INSTANCE //
|
||||
, GeoJsonToDbObjectConverter.INSTANCE //
|
||||
, GeoJsonPointToDbObjectConverter.INSTANCE //
|
||||
, GeoJsonPolygonToDbObjectConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonPointConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonPolygonConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonLineStringConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonMultiLineStringConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonMultiPointConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonMultiPolygonConverter.INSTANCE //
|
||||
, DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +100,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
|
||||
static enum DbObjectToPointConverter implements Converter<DBObject, Point> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -90,9 +111,13 @@ abstract class GeoConverters {
|
||||
@Override
|
||||
public Point convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(source.keySet().size() == 2, "Source must contain 2 elements");
|
||||
|
||||
return source == null ? null : new Point((Double) source.get("x"), (Double) source.get("y"));
|
||||
return new Point((Double) source.get("x"), (Double) source.get("y"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +127,7 @@ abstract class GeoConverters {
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
|
||||
static enum PointToDbObjectConverter implements Converter<Point, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -123,7 +148,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@WritingConverter
|
||||
public static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
|
||||
static enum BoxToDbObjectConverter implements Converter<Box, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -152,7 +177,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
|
||||
static enum DbObjectToBoxConverter implements Converter<DBObject, Box> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -180,7 +205,7 @@ abstract class GeoConverters {
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
|
||||
static enum CircleToDbObjectConverter implements Converter<Circle, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -210,7 +235,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
|
||||
static enum DbObjectToCircleConverter implements Converter<DBObject, Circle> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -251,7 +276,7 @@ abstract class GeoConverters {
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
|
||||
static enum SphereToDbObjectConverter implements Converter<Sphere, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -281,7 +306,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
|
||||
static enum DbObjectToSphereConverter implements Converter<DBObject, Sphere> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -322,7 +347,7 @@ abstract class GeoConverters {
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
|
||||
static enum PolygonToDbObjectConverter implements Converter<Polygon, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -357,7 +382,7 @@ abstract class GeoConverters {
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
public static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
|
||||
static enum DbObjectToPolygonConverter implements Converter<DBObject, Polygon> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -392,7 +417,7 @@ abstract class GeoConverters {
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
|
||||
static enum GeoCommandToDbObjectConverter implements Converter<GeoCommand, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -401,6 +426,7 @@ abstract class GeoConverters {
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public DBObject convert(GeoCommand source) {
|
||||
|
||||
if (source == null) {
|
||||
@@ -411,6 +437,10 @@ abstract class GeoConverters {
|
||||
|
||||
Shape shape = source.getShape();
|
||||
|
||||
if (shape instanceof GeoJson) {
|
||||
return GeoJsonToDbObjectConverter.INSTANCE.convert((GeoJson) shape);
|
||||
}
|
||||
|
||||
if (shape instanceof Box) {
|
||||
|
||||
argument.add(toList(((Box) shape).getFirst()));
|
||||
@@ -442,7 +472,377 @@ abstract class GeoConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
static enum GeoJsonToDbObjectConverter implements Converter<GeoJson, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public DBObject convert(GeoJson source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DBObject dbo = new BasicDBObject("type", source.getType());
|
||||
|
||||
if (source instanceof GeoJsonGeometryCollection) {
|
||||
|
||||
BasicDBList dbl = new BasicDBList();
|
||||
|
||||
for (GeoJson geometry : ((GeoJsonGeometryCollection) source).getCoordinates()) {
|
||||
dbl.add(convert(geometry));
|
||||
}
|
||||
|
||||
dbo.put("geometries", dbl);
|
||||
|
||||
} else {
|
||||
dbo.put("coordinates", convertIfNecessarry(source.getCoordinates()));
|
||||
}
|
||||
|
||||
return dbo;
|
||||
}
|
||||
|
||||
private Object convertIfNecessarry(Object candidate) {
|
||||
|
||||
if (candidate instanceof GeoJson) {
|
||||
return convertIfNecessarry(((GeoJson) candidate).getCoordinates());
|
||||
}
|
||||
|
||||
if (candidate instanceof Iterable) {
|
||||
|
||||
BasicDBList dbl = new BasicDBList();
|
||||
|
||||
for (Object element : (Iterable) candidate) {
|
||||
dbl.add(convertIfNecessarry(element));
|
||||
}
|
||||
|
||||
return dbl;
|
||||
}
|
||||
|
||||
if (candidate instanceof Point) {
|
||||
return toList((Point) candidate);
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum GeoJsonPointToDbObjectConverter implements Converter<GeoJsonPoint, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public DBObject convert(GeoJsonPoint source) {
|
||||
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum GeoJsonPolygonToDbObjectConverter implements Converter<GeoJsonPolygon, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public DBObject convert(GeoJsonPolygon source) {
|
||||
return GeoJsonToDbObjectConverter.INSTANCE.convert(source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonPointConverter implements Converter<DBObject, GeoJsonPoint> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public GeoJsonPoint convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Point"),
|
||||
String.format("Cannot convert type '%s' to Point.", source.get("type")));
|
||||
|
||||
List<Double> dbl = (List<Double>) source.get("coordinates");
|
||||
return new GeoJsonPoint(dbl.get(0).doubleValue(), dbl.get(1).doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonPolygonConverter implements Converter<DBObject, GeoJsonPolygon> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public GeoJsonPolygon convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "Polygon"),
|
||||
String.format("Cannot convert type '%s' to Polygon.", source.get("type")));
|
||||
|
||||
return toGeoJsonPolygon((BasicDBList) source.get("coordinates"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonMultiPolygonConverter implements Converter<DBObject, GeoJsonMultiPolygon> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public GeoJsonMultiPolygon convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPolygon"),
|
||||
String.format("Cannot convert type '%s' to MultiPolygon.", source.get("type")));
|
||||
|
||||
BasicDBList dbl = (BasicDBList) source.get("coordinates");
|
||||
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>();
|
||||
|
||||
for (Object polygon : dbl) {
|
||||
polygones.add(toGeoJsonPolygon((BasicDBList) polygon));
|
||||
}
|
||||
|
||||
return new GeoJsonMultiPolygon(polygones);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonLineStringConverter implements Converter<DBObject, GeoJsonLineString> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public GeoJsonLineString convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "LineString"),
|
||||
String.format("Cannot convert type '%s' to LineString.", source.get("type")));
|
||||
|
||||
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||
|
||||
return new GeoJsonLineString(toListOfPoint(cords));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonMultiPointConverter implements Converter<DBObject, GeoJsonMultiPoint> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public GeoJsonMultiPoint convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiPoint"),
|
||||
String.format("Cannot convert type '%s' to MultiPoint.", source.get("type")));
|
||||
|
||||
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||
|
||||
return new GeoJsonMultiPoint(toListOfPoint(cords));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonMultiLineStringConverter implements Converter<DBObject, GeoJsonMultiLineString> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public GeoJsonMultiLineString convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "MultiLineString"),
|
||||
String.format("Cannot convert type '%s' to MultiLineString.", source.get("type")));
|
||||
|
||||
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>();
|
||||
BasicDBList cords = (BasicDBList) source.get("coordinates");
|
||||
|
||||
for (Object line : cords) {
|
||||
lines.add(new GeoJsonLineString(toListOfPoint((BasicDBList) line)));
|
||||
}
|
||||
return new GeoJsonMultiLineString(lines);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
static enum DbObjectToGeoJsonGeometryCollectionConverter implements Converter<DBObject, GeoJsonGeometryCollection> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public GeoJsonGeometryCollection convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(source.get("type"), "GeometryCollection"),
|
||||
String.format("Cannot convert type '%s' to GeometryCollection.", source.get("type")));
|
||||
|
||||
List<GeoJson<?>> geometries = new ArrayList<GeoJson<?>>();
|
||||
for (Object o : (List) source.get("geometries")) {
|
||||
geometries.add(convertGeometries((DBObject) o));
|
||||
}
|
||||
return new GeoJsonGeometryCollection(geometries);
|
||||
|
||||
}
|
||||
|
||||
private static GeoJson<?> convertGeometries(DBObject source) {
|
||||
|
||||
Object type = source.get("type");
|
||||
if (ObjectUtils.nullSafeEquals(type, "Point")) {
|
||||
return DbObjectToGeoJsonPointConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(type, "MultiPoint")) {
|
||||
return DbObjectToGeoJsonMultiPointConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(type, "LineString")) {
|
||||
return DbObjectToGeoJsonLineStringConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(type, "MultiLineString")) {
|
||||
return DbObjectToGeoJsonMultiLineStringConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(type, "Polygon")) {
|
||||
return DbObjectToGeoJsonPolygonConverter.INSTANCE.convert(source);
|
||||
}
|
||||
if (ObjectUtils.nullSafeEquals(type, "MultiPolygon")) {
|
||||
return DbObjectToGeoJsonMultiPolygonConverter.INSTANCE.convert(source);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Cannot convert unknown GeoJson type %s", type));
|
||||
}
|
||||
}
|
||||
|
||||
static List<Double> toList(Point point) {
|
||||
return Arrays.asList(point.getX(), point.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPoint}s.
|
||||
*
|
||||
* @param listOfCoordinatePairs
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Point> toListOfPoint(BasicDBList listOfCoordinatePairs) {
|
||||
|
||||
List<Point> points = new ArrayList<Point>();
|
||||
|
||||
for (Object point : listOfCoordinatePairs) {
|
||||
|
||||
Assert.isInstanceOf(List.class, point);
|
||||
|
||||
List<Double> coordinatesList = (List<Double>) point;
|
||||
|
||||
points.add(new GeoJsonPoint(coordinatesList.get(0).doubleValue(), coordinatesList.get(1).doubleValue()));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPolygon}.
|
||||
*
|
||||
* @param dbList
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
static GeoJsonPolygon toGeoJsonPolygon(BasicDBList dbList) {
|
||||
return new GeoJsonPolygon(toListOfPoint((BasicDBList) dbList.get(0)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 by the original author(s).
|
||||
* Copyright 2011-2015 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -136,8 +136,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param typeMapper the typeMapper to set
|
||||
*/
|
||||
public void setTypeMapper(MongoTypeMapper typeMapper) {
|
||||
this.typeMapper = typeMapper == null ? new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY,
|
||||
mappingContext) : typeMapper;
|
||||
this.typeMapper = typeMapper == null
|
||||
? new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext) : typeMapper;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -238,7 +238,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<MongoPersistentProperty>(
|
||||
entity, provider, path.getCurrentObject());
|
||||
|
||||
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider, path);
|
||||
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider,
|
||||
path);
|
||||
}
|
||||
|
||||
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final ObjectPath path) {
|
||||
@@ -263,7 +264,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
accessor.setProperty(idProperty, idValue);
|
||||
}
|
||||
|
||||
final ObjectPath currentPath = path.push(result, entity, idValue);
|
||||
final ObjectPath currentPath = path.push(result, entity,
|
||||
idValue != null ? dbo.get(idProperty.getFieldName()) : null);
|
||||
|
||||
// Set properties not already set in the constructor
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
@@ -289,7 +291,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
final MongoPersistentProperty property = association.getInverse();
|
||||
Object value = dbo.get(property.getFieldName());
|
||||
|
||||
if (value == null) {
|
||||
if (value == null || entity.isConstructorArgument(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -510,8 +512,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
: new BasicDBObject();
|
||||
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, propDbObj);
|
||||
|
||||
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass()) ? mappingContext
|
||||
.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
|
||||
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass())
|
||||
? mappingContext.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
|
||||
|
||||
writeInternal(obj, propDbObj, entity);
|
||||
accessor.put(prop, propDbObj);
|
||||
@@ -591,7 +593,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
if (conversions.isSimpleType(key.getClass())) {
|
||||
|
||||
String simpleKey = potentiallyEscapeMapKey(key.toString());
|
||||
String simpleKey = prepareMapKey(key.toString());
|
||||
dbObject.put(simpleKey, value != null ? createDBRef(value, property) : null);
|
||||
|
||||
} else {
|
||||
@@ -643,12 +645,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeInformation<?> propertyType) {
|
||||
|
||||
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
|
||||
|
||||
Object key = entry.getKey();
|
||||
Object val = entry.getValue();
|
||||
|
||||
if (conversions.isSimpleType(key.getClass())) {
|
||||
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
|
||||
// being convertable
|
||||
String simpleKey = potentiallyEscapeMapKey(key.toString());
|
||||
|
||||
String simpleKey = prepareMapKey(key);
|
||||
if (val == null || conversions.isSimpleType(val.getClass())) {
|
||||
writeSimpleInternal(val, dbo, simpleKey);
|
||||
} else if (val instanceof Collection || val.getClass().isArray()) {
|
||||
@@ -669,6 +672,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return dbo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the given {@link Map} key to be converted into a {@link String}. Will invoke potentially registered custom
|
||||
* conversions and escape dots from the result as they're not supported as {@link Map} key in MongoDB.
|
||||
*
|
||||
* @param key must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private String prepareMapKey(Object key) {
|
||||
|
||||
Assert.notNull(key, "Map key must not be null!");
|
||||
|
||||
String convertedKey = potentiallyConvertMapKey(key);
|
||||
return potentiallyEscapeMapKey(convertedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
|
||||
* conversion if none is configured.
|
||||
@@ -684,13 +702,31 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
if (mapKeyDotReplacement == null) {
|
||||
throw new MappingException(String.format("Map key %s contains dots but no replacement was configured! Make "
|
||||
+ "sure map keys don't contain dots in the first place or configure an appropriate replacement!", source));
|
||||
throw new MappingException(String.format(
|
||||
"Map key %s contains dots but no replacement was configured! Make "
|
||||
+ "sure map keys don't contain dots in the first place or configure an appropriate replacement!",
|
||||
source));
|
||||
}
|
||||
|
||||
return source.replaceAll("\\.", mapKeyDotReplacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} representation of the given {@link Map} key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private String potentiallyConvertMapKey(Object key) {
|
||||
|
||||
if (key instanceof String) {
|
||||
return (String) key;
|
||||
}
|
||||
|
||||
return conversions.hasCustomWriteTarget(key.getClass(), String.class)
|
||||
? (String) getPotentiallyConvertedSimpleWrite(key) : key.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the map key replacements in the given key just read with a dot in case a map key replacement has been
|
||||
* configured.
|
||||
@@ -771,7 +807,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
|
||||
|
||||
if (value == null || target == null) {
|
||||
if (value == null || target == null || target.isAssignableFrom(value.getClass())) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -783,7 +819,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return Enum.valueOf((Class<Enum>) target, value.toString());
|
||||
}
|
||||
|
||||
return target.isAssignableFrom(value.getClass()) ? value : conversionService.convert(value, target);
|
||||
return conversionService.convert(value, target);
|
||||
}
|
||||
|
||||
protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
|
||||
@@ -857,16 +893,16 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Class<?> rawComponentType = componentType == null ? null : componentType.getType();
|
||||
|
||||
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory
|
||||
.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>()
|
||||
: CollectionFactory.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||
|
||||
for (int i = 0; i < sourceValue.size(); i++) {
|
||||
|
||||
Object dbObjItem = sourceValue.get(i);
|
||||
|
||||
if (dbObjItem instanceof DBRef) {
|
||||
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem),
|
||||
path));
|
||||
items.add(
|
||||
DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem), path));
|
||||
} else if (dbObjItem instanceof DBObject) {
|
||||
items.add(read(componentType, (DBObject) dbObjItem, path));
|
||||
} else {
|
||||
@@ -984,10 +1020,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
this.write(obj, newDbo);
|
||||
|
||||
if (typeInformation == null) {
|
||||
return removeTypeInfoRecursively(newDbo);
|
||||
return removeTypeInfo(newDbo, true);
|
||||
}
|
||||
|
||||
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfoRecursively(newDbo);
|
||||
if (typeInformation.getType().equals(NestedDocument.class)) {
|
||||
return removeTypeInfo(newDbo, false);
|
||||
}
|
||||
|
||||
return !obj.getClass().equals(typeInformation.getType()) ? newDbo : removeTypeInfo(newDbo, true);
|
||||
}
|
||||
|
||||
public BasicDBList maybeConvertList(Iterable<?> source, TypeInformation<?> typeInformation) {
|
||||
@@ -1001,12 +1041,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the type information from the conversion result.
|
||||
* Removes the type information from the entire conversion result.
|
||||
*
|
||||
* @param object
|
||||
* @param recursively whether to apply the removal recursively
|
||||
* @return
|
||||
*/
|
||||
private Object removeTypeInfoRecursively(Object object) {
|
||||
private Object removeTypeInfo(Object object, boolean recursively) {
|
||||
|
||||
if (!(object instanceof DBObject)) {
|
||||
return object;
|
||||
@@ -1014,19 +1055,29 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
DBObject dbObject = (DBObject) object;
|
||||
String keyToRemove = null;
|
||||
|
||||
for (String key : dbObject.keySet()) {
|
||||
|
||||
if (typeMapper.isTypeKey(key)) {
|
||||
keyToRemove = key;
|
||||
if (recursively) {
|
||||
|
||||
Object value = dbObject.get(key);
|
||||
|
||||
if (value instanceof BasicDBList) {
|
||||
for (Object element : (BasicDBList) value) {
|
||||
removeTypeInfo(element, recursively);
|
||||
}
|
||||
} else {
|
||||
removeTypeInfo(value, recursively);
|
||||
}
|
||||
}
|
||||
|
||||
Object value = dbObject.get(key);
|
||||
if (value instanceof BasicDBList) {
|
||||
for (Object element : (BasicDBList) value) {
|
||||
removeTypeInfoRecursively(element);
|
||||
if (typeMapper.isTypeKey(key)) {
|
||||
|
||||
keyToRemove = key;
|
||||
|
||||
if (!recursively) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
removeTypeInfoRecursively(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,8 +1141,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private class ConverterAwareSpELExpressionParameterValueProvider extends
|
||||
SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
||||
private class ConverterAwareSpELExpressionParameterValueProvider
|
||||
extends SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
||||
|
||||
private final ObjectPath path;
|
||||
|
||||
@@ -1103,7 +1154,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator,
|
||||
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate, ObjectPath path) {
|
||||
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate,
|
||||
ObjectPath path) {
|
||||
|
||||
super(evaluator, conversionService, delegate);
|
||||
this.path = path;
|
||||
@@ -1144,11 +1196,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return (T) dbref;
|
||||
}
|
||||
|
||||
Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getRef());
|
||||
|
||||
if (object != null) {
|
||||
return (T) object;
|
||||
}
|
||||
Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getCollectionName());
|
||||
|
||||
return (T) (object != null ? object : read(type, readRef(dbref), path));
|
||||
}
|
||||
@@ -1160,6 +1208,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @return
|
||||
*/
|
||||
DBObject readRef(DBRef ref) {
|
||||
return ref.fetch();
|
||||
return dbRefResolver.fetch(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker class used to indicate we have a non root document object here that might be used within an update - so we
|
||||
* need to preserve type hints for potential nested elements but need to remove it on top level.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.8
|
||||
*/
|
||||
static class NestedDocument {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -20,6 +20,7 @@ import java.math.BigInteger;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.bson.types.Code;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
@@ -27,8 +28,11 @@ import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.mongodb.core.query.Term;
|
||||
import org.springframework.data.mongodb.core.script.NamedMongoScript;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
@@ -178,4 +182,50 @@ abstract class MongoConverters {
|
||||
return source == null ? null : source.getFormatted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public static enum DBObjectToNamedMongoScriptCoverter implements Converter<DBObject, NamedMongoScript> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public NamedMongoScript convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String id = source.get("_id").toString();
|
||||
Object rawValue = source.get("value");
|
||||
|
||||
return new NamedMongoScript(id, ((Code) rawValue).getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public static enum NamedMongoScriptToDBObjectConverter implements Converter<NamedMongoScript, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public DBObject convert(NamedMongoScript source) {
|
||||
|
||||
if (source == null) {
|
||||
return new BasicDBObject();
|
||||
}
|
||||
|
||||
BasicDBObjectBuilder builder = new BasicDBObjectBuilder();
|
||||
|
||||
builder.append("_id", source.getName());
|
||||
builder.append("value", new Code(source.getCode()));
|
||||
|
||||
return builder.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -34,10 +34,13 @@ import org.springframework.data.mapping.PropertyReferenceException;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter.NestedDocument;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
@@ -58,6 +61,7 @@ public class QueryMapper {
|
||||
|
||||
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
|
||||
private static final DBObject META_TEXT_SCORE = new BasicDBObject("$meta", "textScore");
|
||||
static final ClassTypeInformation<?> NESTED_DOCUMENT = ClassTypeInformation.from(NestedDocument.class);
|
||||
|
||||
private enum MetaMapping {
|
||||
FORCE, WHEN_PRESENT, IGNORE;
|
||||
@@ -250,8 +254,8 @@ public class QueryMapper {
|
||||
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
|
||||
Object value = keyword.getValue();
|
||||
|
||||
Object convertedValue = needsAssociationConversion ? convertAssociation(value, property) : getMappedValue(
|
||||
property.with(keyword.getKey()), value);
|
||||
Object convertedValue = needsAssociationConversion ? convertAssociation(value, property)
|
||||
: getMappedValue(property.with(keyword.getKey()), value);
|
||||
|
||||
return new BasicDBObject(keyword.key, convertedValue);
|
||||
}
|
||||
@@ -390,7 +394,7 @@ public class QueryMapper {
|
||||
if (source instanceof DBRef) {
|
||||
|
||||
DBRef ref = (DBRef) source;
|
||||
return new DBRef(ref.getDB(), ref.getRef(), convertId(ref.getId()));
|
||||
return new DBRef(ref.getCollectionName(), convertId(ref.getId()));
|
||||
}
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
@@ -464,13 +468,20 @@ public class QueryMapper {
|
||||
*/
|
||||
public Object convertId(Object id) {
|
||||
|
||||
try {
|
||||
return conversionService.convert(id, ObjectId.class);
|
||||
} catch (ConversionException e) {
|
||||
// Ignore
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return delegateConvertToMongoType(id, null);
|
||||
if (id instanceof String) {
|
||||
return ObjectId.isValid(id.toString()) ? conversionService.convert(id, ObjectId.class) : id;
|
||||
}
|
||||
|
||||
try {
|
||||
return conversionService.canConvert(id.getClass(), ObjectId.class) ? conversionService.convert(id, ObjectId.class)
|
||||
: delegateConvertToMongoType(id, null);
|
||||
} catch (ConversionException o_O) {
|
||||
return delegateConvertToMongoType(id, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,6 +661,10 @@ public class QueryMapper {
|
||||
public Association<MongoPersistentProperty> getAssociation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeInformation<?> getTypeHint() {
|
||||
return ClassTypeInformation.OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -809,7 +824,7 @@ public class QueryMapper {
|
||||
|
||||
try {
|
||||
|
||||
PropertyPath path = PropertyPath.from(pathExpression, entity.getTypeInformation());
|
||||
PropertyPath path = PropertyPath.from(pathExpression.replaceAll("\\.\\d", ""), entity.getTypeInformation());
|
||||
PersistentPropertyPath<MongoPersistentProperty> propertyPath = mappingContext.getPersistentPropertyPath(path);
|
||||
|
||||
Iterator<MongoPersistentProperty> iterator = propertyPath.iterator();
|
||||
@@ -842,7 +857,7 @@ public class QueryMapper {
|
||||
* @return
|
||||
*/
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return PropertyToFieldNameConverter.INSTANCE;
|
||||
return new PositionParameterRetainingPropertyKeyConverter(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,6 +870,104 @@ public class QueryMapper {
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new AssociationConverter(getAssociation());
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.8
|
||||
*/
|
||||
static class PositionParameterRetainingPropertyKeyConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final KeyMapper keyMapper;
|
||||
|
||||
public PositionParameterRetainingPropertyKeyConverter(String rawKey) {
|
||||
this.keyMapper = new KeyMapper(rawKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
return keyMapper.mapPropertyName(source);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getTypeHint()
|
||||
*/
|
||||
@Override
|
||||
public TypeInformation<?> getTypeHint() {
|
||||
|
||||
MongoPersistentProperty property = getProperty();
|
||||
|
||||
if (property == null) {
|
||||
return super.getTypeHint();
|
||||
}
|
||||
|
||||
if (property.getActualType().isInterface()
|
||||
|| java.lang.reflect.Modifier.isAbstract(property.getActualType().getModifiers())) {
|
||||
return ClassTypeInformation.OBJECT;
|
||||
}
|
||||
|
||||
return NESTED_DOCUMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.8
|
||||
*/
|
||||
static class KeyMapper {
|
||||
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
public KeyMapper(String key) {
|
||||
|
||||
this.iterator = Arrays.asList(key.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||
|
||||
StringBuilder mappedName = new StringBuilder(PropertyToFieldNameConverter.INSTANCE.convert(property));
|
||||
boolean inspect = iterator.hasNext();
|
||||
|
||||
while (inspect) {
|
||||
|
||||
String partial = iterator.next();
|
||||
boolean isPositional = (isPositionalParameter(partial) && (property.isMap() || property.isCollectionLike()));
|
||||
|
||||
if (isPositional) {
|
||||
mappedName.append(".").append(partial);
|
||||
}
|
||||
|
||||
inspect = isPositional && iterator.hasNext();
|
||||
}
|
||||
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
private static boolean isPositionalParameter(String partial) {
|
||||
|
||||
if ("$".equals(partial)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Long.valueOf(partial);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveDBRefResolver} provides reflective access to {@link DBRef} API that is not consistently available
|
||||
* for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class ReflectiveDBRefResolver {
|
||||
|
||||
private static final Method FETCH_METHOD;
|
||||
|
||||
static {
|
||||
FETCH_METHOD = findMethod(DBRef.class, "fetch");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the object referenced from the database either be directly calling {@link DBRef#fetch()} or
|
||||
* {@link DBCollection#findOne(Object)}.
|
||||
*
|
||||
* @param db can be {@literal null} when using MongoDB Java driver in version 2.x.
|
||||
* @param ref must not be {@literal null}.
|
||||
* @return the document that this references.
|
||||
*/
|
||||
public static DBObject fetch(MongoDbFactory factory, DBRef ref) {
|
||||
|
||||
Assert.notNull(ref, "DBRef to fetch must not be null!");
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
|
||||
Assert.notNull(factory, "DbFactory to fetch DB from must not be null!");
|
||||
return factory.getDb().getCollection(ref.getCollectionName()).findOne(ref.getId());
|
||||
}
|
||||
|
||||
return (DBObject) invokeMethod(FETCH_METHOD, ref);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -24,12 +22,11 @@ import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update.Modifier;
|
||||
import org.springframework.data.mongodb.core.query.Update.Modifiers;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
@@ -65,8 +62,8 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Object delegateConvertToMongoType(Object source, MongoPersistentEntity<?> entity) {
|
||||
return entity == null ? super.delegateConvertToMongoType(source, null) : converter.convertToMongoType(source,
|
||||
entity.getTypeInformation());
|
||||
return converter.convertToMongoType(source,
|
||||
entity == null ? ClassTypeInformation.OBJECT : getTypeHintForEntity(source, entity));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -89,7 +86,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
return getMappedUpdateModifier(field, rawValue);
|
||||
}
|
||||
|
||||
return super.getMappedObjectForField(field, getMappedValue(field, rawValue));
|
||||
return super.getMappedObjectForField(field, rawValue);
|
||||
}
|
||||
|
||||
private Entry<String, Object> getMappedUpdateModifier(Field field, Object rawValue) {
|
||||
@@ -97,14 +94,14 @@ public class UpdateMapper extends QueryMapper {
|
||||
|
||||
if (rawValue instanceof Modifier) {
|
||||
|
||||
value = getMappedValue((Modifier) rawValue);
|
||||
value = getMappedValue(field, (Modifier) rawValue);
|
||||
|
||||
} else if (rawValue instanceof Modifiers) {
|
||||
|
||||
DBObject modificationOperations = new BasicDBObject();
|
||||
|
||||
for (Modifier modifier : ((Modifiers) rawValue).getModifiers()) {
|
||||
modificationOperations.putAll(getMappedValue(modifier).toMap());
|
||||
modificationOperations.putAll(getMappedValue(field, modifier).toMap());
|
||||
}
|
||||
|
||||
value = modificationOperations;
|
||||
@@ -132,12 +129,30 @@ public class UpdateMapper extends QueryMapper {
|
||||
return value instanceof Query;
|
||||
}
|
||||
|
||||
private DBObject getMappedValue(Modifier modifier) {
|
||||
private DBObject getMappedValue(Field field, Modifier modifier) {
|
||||
|
||||
Object value = converter.convertToMongoType(modifier.getValue(), ClassTypeInformation.OBJECT);
|
||||
TypeInformation<?> typeHint = field == null ? ClassTypeInformation.OBJECT : field.getTypeHint();
|
||||
|
||||
Object value = converter.convertToMongoType(modifier.getValue(), typeHint);
|
||||
return new BasicDBObject(modifier.getKey(), value);
|
||||
}
|
||||
|
||||
private TypeInformation<?> getTypeHintForEntity(Object source, MongoPersistentEntity<?> entity) {
|
||||
|
||||
TypeInformation<?> info = entity.getTypeInformation();
|
||||
Class<?> type = info.getActualType().getType();
|
||||
|
||||
if (source == null || type.isInterface() || java.lang.reflect.Modifier.isAbstract(type.getModifiers())) {
|
||||
return info;
|
||||
}
|
||||
|
||||
if (!type.equals(source.getClass())) {
|
||||
return info;
|
||||
}
|
||||
|
||||
return NESTED_DOCUMENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper#createPropertyField(org.springframework.data.mongodb.core.mapping.MongoPersistentEntity, java.lang.String, org.springframework.data.mapping.context.MappingContext)
|
||||
@@ -146,8 +161,8 @@ public class UpdateMapper extends QueryMapper {
|
||||
protected Field createPropertyField(MongoPersistentEntity<?> entity, String key,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
return entity == null ? super.createPropertyField(entity, key, mappingContext) : //
|
||||
new MetadataBackedUpdateField(entity, key, mappingContext);
|
||||
return entity == null ? super.createPropertyField(entity, key, mappingContext)
|
||||
: new MetadataBackedUpdateField(entity, key, mappingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +209,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return new UpdatePropertyConverter(key);
|
||||
return new PositionParameterRetainingPropertyKeyConverter(key);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,71 +221,6 @@ public class UpdateMapper extends QueryMapper {
|
||||
return new UpdateAssociationConverter(getAssociation(), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special mapper handling positional parameter {@literal $} within property names.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class UpdateKeyMapper {
|
||||
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
protected UpdateKeyMapper(String rawKey) {
|
||||
|
||||
Assert.hasText(rawKey, "Key must not be null or empty!");
|
||||
|
||||
this.iterator = Arrays.asList(rawKey.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||
|
||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Special {@link Converter} for {@link MongoPersistentProperty} instances that will concatenate the {@literal $}
|
||||
* contained in the source update key.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final UpdateKeyMapper mapper;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
||||
*
|
||||
* @param updateKey must not be {@literal null} or empty.
|
||||
*/
|
||||
public UpdatePropertyConverter(String updateKey) {
|
||||
|
||||
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
||||
|
||||
this.mapper = new UpdateKeyMapper(updateKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty property) {
|
||||
return mapper.mapPropertyName(property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Converter} retaining positional parameter {@literal $} for {@link Association}s.
|
||||
*
|
||||
@@ -278,7 +228,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
protected static class UpdateAssociationConverter extends AssociationConverter {
|
||||
|
||||
private final UpdateKeyMapper mapper;
|
||||
private final KeyMapper mapper;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
@@ -288,7 +238,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
|
||||
|
||||
super(association);
|
||||
this.mapper = new UpdateKeyMapper(key);
|
||||
this.mapper = new KeyMapper(key);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
/**
|
||||
* Interface definition for structures defined in GeoJSON ({@link http://geojson.org/}) format.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public interface GeoJson<T extends Iterable<?>> {
|
||||
|
||||
/**
|
||||
* String value representing the type of the {@link GeoJson} object.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
* @see http://geojson.org/geojson-spec.html#geojson-objects
|
||||
*/
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* The value of the coordinates member is always an {@link Iterable}. The structure for the elements within is
|
||||
* determined by {@link #getType()} of geometry.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
* @see http://geojson.org/geojson-spec.html#geometry-objects
|
||||
*/
|
||||
T getCoordinates();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Defines a {@link GeoJsonGeometryCollection} that consists of a {@link List} of {@link GeoJson} objects.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#geometry-collection
|
||||
*/
|
||||
public class GeoJsonGeometryCollection implements GeoJson<Iterable<GeoJson<?>>> {
|
||||
|
||||
private static final String TYPE = "GeometryCollection";
|
||||
|
||||
private final List<GeoJson<?>> geometries = new ArrayList<GeoJson<?>>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonGeometryCollection} for the given {@link GeoJson} instances.
|
||||
*
|
||||
* @param geometries
|
||||
*/
|
||||
public GeoJsonGeometryCollection(List<GeoJson<?>> geometries) {
|
||||
|
||||
Assert.notNull(geometries, "Geometries must not be null!");
|
||||
|
||||
this.geometries.addAll(geometries);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<GeoJson<?>> getCoordinates() {
|
||||
return Collections.unmodifiableList(this.geometries);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.geometries);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoJsonGeometryCollection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeoJsonGeometryCollection other = (GeoJsonGeometryCollection) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.geometries, other.geometries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* {@link GeoJsonLineString} is defined as list of at least 2 {@link Point}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#linestring
|
||||
*/
|
||||
public class GeoJsonLineString extends GeoJsonMultiPoint {
|
||||
|
||||
private static final String TYPE = "LineString";
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonLineString} for the given {@link Point}s.
|
||||
*
|
||||
* @param points must not be {@literal null} and have at least 2 entries.
|
||||
*/
|
||||
public GeoJsonLineString(List<Point> points) {
|
||||
super(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonLineString} for the given {@link Point}s.
|
||||
*
|
||||
* @param first must not be {@literal null}
|
||||
* @param second must not be {@literal null}
|
||||
* @param others can be {@literal null}
|
||||
*/
|
||||
public GeoJsonLineString(Point first, Point second, Point... others) {
|
||||
super(first, second, others);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* A Jackson {@link Module} to register custom {@link JsonSerializer} and {@link JsonDeserializer}s for GeoJSON types.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class GeoJsonModule extends SimpleModule {
|
||||
|
||||
private static final long serialVersionUID = -8723016728655643720L;
|
||||
|
||||
public GeoJsonModule() {
|
||||
|
||||
addDeserializer(GeoJsonPoint.class, new GeoJsonPointDeserializer());
|
||||
addDeserializer(GeoJsonMultiPoint.class, new GeoJsonMultiPointDeserializer());
|
||||
addDeserializer(GeoJsonLineString.class, new GeoJsonLineStringDeserializer());
|
||||
addDeserializer(GeoJsonMultiLineString.class, new GeoJsonMultiLineStringDeserializer());
|
||||
addDeserializer(GeoJsonPolygon.class, new GeoJsonPolygonDeserializer());
|
||||
addDeserializer(GeoJsonMultiPolygon.class, new GeoJsonMultiPolygonDeserializer());
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static abstract class GeoJsonDeserializer<T extends GeoJson<?>> extends JsonDeserializer<T> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
|
||||
*/
|
||||
@Override
|
||||
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
|
||||
JsonNode node = jp.readValueAsTree();
|
||||
JsonNode coordinates = node.get("coordinates");
|
||||
|
||||
if (coordinates != null && coordinates.isArray()) {
|
||||
return doDeserialize((ArrayNode) coordinates);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual deserialization given the {@literal coordinates} as {@link ArrayNode}.
|
||||
*
|
||||
* @param coordinates
|
||||
* @return
|
||||
*/
|
||||
protected abstract T doDeserialize(ArrayNode coordinates);
|
||||
|
||||
/**
|
||||
* Get the {@link GeoJsonPoint} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
|
||||
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal null} when given a {@code null} value.
|
||||
*/
|
||||
protected GeoJsonPoint toGeoJsonPoint(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GeoJsonPoint(node.get(0).asDouble(), node.get(1).asDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Point} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
|
||||
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal null} when given a {@code null} value.
|
||||
*/
|
||||
protected Point toPoint(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Point(node.get(0).asDouble(), node.get(1).asDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the points nested within given {@link ArrayNode}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal empty list} when given a {@code null} value.
|
||||
*/
|
||||
protected List<Point> toPoints(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Point> points = new ArrayList<Point>(node.size());
|
||||
|
||||
for (JsonNode coordinatePair : node) {
|
||||
if (coordinatePair.isArray()) {
|
||||
points.add(toPoint((ArrayNode) coordinatePair));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
protected GeoJsonLineString toLineString(ArrayNode node) {
|
||||
return new GeoJsonLineString(toPoints((ArrayNode) node));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Point}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* { "type": "Point", "coordinates": [10.0, 20.0] }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonPointDeserializer extends GeoJsonDeserializer<GeoJsonPoint> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonPoint doDeserialize(ArrayNode coordinates) {
|
||||
return toGeoJsonPoint(coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal LineString}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "LineString",
|
||||
* "coordinates": [
|
||||
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonLineStringDeserializer extends GeoJsonDeserializer<GeoJsonLineString> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonLineString doDeserialize(ArrayNode coordinates) {
|
||||
return new GeoJsonLineString(toPoints(coordinates));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPoint}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiPoint",
|
||||
* "coordinates": [
|
||||
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiPointDeserializer extends GeoJsonDeserializer<GeoJsonMultiPoint> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiPoint doDeserialize(ArrayNode coordinates) {
|
||||
return new GeoJsonMultiPoint(toPoints(coordinates));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiLineString}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiLineString",
|
||||
* "coordinates": [
|
||||
* [ [10.0, 20.0], [30.0, 40.0] ],
|
||||
* [ [50.0, 60.0] , [70.0, 80.0] ]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiLineStringDeserializer extends GeoJsonDeserializer<GeoJsonMultiLineString> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiLineString doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>(coordinates.size());
|
||||
|
||||
for (JsonNode lineString : coordinates) {
|
||||
if (lineString.isArray()) {
|
||||
lines.add(toLineString((ArrayNode) lineString));
|
||||
}
|
||||
}
|
||||
|
||||
return new GeoJsonMultiLineString(lines);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Polygon}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "Polygon",
|
||||
* "coordinates": [
|
||||
* [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonPolygonDeserializer extends GeoJsonDeserializer<GeoJsonPolygon> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonPolygon doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
for (JsonNode ring : coordinates) {
|
||||
|
||||
// currently we do not support holes in polygons.
|
||||
return new GeoJsonPolygon(toPoints((ArrayNode) ring));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPolygon}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiPolygon",
|
||||
* "coordinates": [
|
||||
* [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
|
||||
* [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
|
||||
* [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiPolygonDeserializer extends GeoJsonDeserializer<GeoJsonMultiPolygon> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiPolygon doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>(coordinates.size());
|
||||
|
||||
for (JsonNode polygon : coordinates) {
|
||||
for (JsonNode ring : (ArrayNode) polygon) {
|
||||
polygones.add(new GeoJsonPolygon(toPoints((ArrayNode) ring)));
|
||||
}
|
||||
}
|
||||
|
||||
return new GeoJsonMultiPolygon(polygones);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link GeoJsonMultiLineString} is defined as list of {@link GeoJsonLineString}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#multilinestring
|
||||
*/
|
||||
public class GeoJsonMultiLineString implements GeoJson<Iterable<GeoJsonLineString>> {
|
||||
|
||||
private static final String TYPE = "MultiLineString";
|
||||
|
||||
private List<GeoJsonLineString> coordinates = new ArrayList<GeoJsonLineString>();
|
||||
|
||||
/**
|
||||
* Creates new {@link GeoJsonMultiLineString} for the given {@link Point}s.
|
||||
*
|
||||
* @param lines must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonMultiLineString(List<Point>... lines) {
|
||||
|
||||
Assert.notEmpty(lines, "Points for MultiLineString must not be null!");
|
||||
|
||||
for (List<Point> line : lines) {
|
||||
this.coordinates.add(new GeoJsonLineString(line));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link GeoJsonMultiLineString} for the given {@link GeoJsonLineString}s.
|
||||
*
|
||||
* @param lines must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonMultiLineString(List<GeoJsonLineString> lines) {
|
||||
|
||||
Assert.notNull(lines, "Lines for MultiLineString must not be null!");
|
||||
|
||||
this.coordinates.addAll(lines);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<GeoJsonLineString> getCoordinates() {
|
||||
return Collections.unmodifiableList(this.coordinates);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.coordinates);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoJsonMultiLineString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.coordinates, ((GeoJsonMultiLineString) obj).coordinates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link GeoJsonMultiPoint} is defined as list of {@link Point}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#multipoint
|
||||
*/
|
||||
public class GeoJsonMultiPoint implements GeoJson<Iterable<Point>> {
|
||||
|
||||
private static final String TYPE = "MultiPoint";
|
||||
|
||||
private final List<Point> points;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s.
|
||||
*
|
||||
* @param points points must not be {@literal null} and have at least 2 entries.
|
||||
*/
|
||||
public GeoJsonMultiPoint(List<Point> points) {
|
||||
|
||||
Assert.notNull(points, "Points must not be null.");
|
||||
Assert.isTrue(points.size() >= 2, "Minimum of 2 Points required.");
|
||||
|
||||
this.points = new ArrayList<Point>(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s.
|
||||
*
|
||||
* @param first must not be {@literal null}.
|
||||
* @param second must not be {@literal null}.
|
||||
* @param others must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonMultiPoint(Point first, Point second, Point... others) {
|
||||
|
||||
Assert.notNull(first, "First point must not be null!");
|
||||
Assert.notNull(second, "Second point must not be null!");
|
||||
Assert.notNull(others, "Additional points must not be null!");
|
||||
|
||||
this.points = new ArrayList<Point>();
|
||||
this.points.add(first);
|
||||
this.points.add(second);
|
||||
this.points.addAll(Arrays.asList(others));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public List<Point> getCoordinates() {
|
||||
return Collections.unmodifiableList(this.points);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.points);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoJsonMultiPoint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.points, ((GeoJsonMultiPoint) obj).points);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link GeoJsonMultiPolygon} is defined as a list of {@link GeoJsonPolygon}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class GeoJsonMultiPolygon implements GeoJson<Iterable<GeoJsonPolygon>> {
|
||||
|
||||
private static final String TYPE = "MultiPolygon";
|
||||
|
||||
private List<GeoJsonPolygon> coordinates = new ArrayList<GeoJsonPolygon>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoJsonMultiPolygon} for the given {@link GeoJsonPolygon}s.
|
||||
*
|
||||
* @param polygons must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonMultiPolygon(List<GeoJsonPolygon> polygons) {
|
||||
|
||||
Assert.notNull(polygons, "Polygons for MultiPolygon must not be null!");
|
||||
|
||||
this.coordinates.addAll(polygons);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public List<GeoJsonPolygon> getCoordinates() {
|
||||
return Collections.unmodifiableList(this.coordinates);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.coordinates);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoJsonMultiPolygon)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.coordinates, ((GeoJsonMultiPolygon) obj).coordinates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* {@link GeoJson} representation of {@link Point}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#point
|
||||
*/
|
||||
public class GeoJsonPoint extends Point implements GeoJson<List<Double>> {
|
||||
|
||||
private static final long serialVersionUID = -8026303425147474002L;
|
||||
|
||||
private static final String TYPE = "Point";
|
||||
|
||||
/**
|
||||
* Creates {@link GeoJsonPoint} for given coordinates.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public GeoJsonPoint(double x, double y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link GeoJsonPoint} for given {@link Point}.
|
||||
*
|
||||
* @param point must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonPoint(Point point) {
|
||||
super(point);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public List<Double> getCoordinates() {
|
||||
return Arrays.asList(Double.valueOf(getX()), Double.valueOf(getY()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
|
||||
/**
|
||||
* {@link GeoJson} representation of {@link Polygon}. Unlike {@link Polygon} the {@link GeoJsonPolygon} requires a
|
||||
* closed border. Which means that the first and last {@link Point} have to have same coordinate pairs.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @see http://geojson.org/geojson-spec.html#polygon
|
||||
*/
|
||||
public class GeoJsonPolygon extends Polygon implements GeoJson<List<GeoJsonLineString>> {
|
||||
|
||||
private static final long serialVersionUID = 3936163018187247185L;
|
||||
private static final String TYPE = "Polygon";
|
||||
|
||||
private List<GeoJsonLineString> coordinates = new ArrayList<GeoJsonLineString>();
|
||||
|
||||
/**
|
||||
* Creates new {@link GeoJsonPolygon} from the given {@link Point}s.
|
||||
*
|
||||
* @param first must not be {@literal null}.
|
||||
* @param second must not be {@literal null}.
|
||||
* @param third must not be {@literal null}.
|
||||
* @param fourth must not be {@literal null}.
|
||||
* @param others can be {@literal null}.
|
||||
*/
|
||||
public GeoJsonPolygon(Point first, Point second, Point third, Point fourth, final Point... others) {
|
||||
this(asList(first, second, third, fourth, others));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link GeoJsonPolygon} from the given {@link Point}s.
|
||||
*
|
||||
* @param points must not be {@literal null}.
|
||||
*/
|
||||
public GeoJsonPolygon(List<Point> points) {
|
||||
|
||||
super(points);
|
||||
this.coordinates.add(new GeoJsonLineString(points));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJson#getCoordinates()
|
||||
*/
|
||||
@Override
|
||||
public List<GeoJsonLineString> getCoordinates() {
|
||||
return Collections.unmodifiableList(this.coordinates);
|
||||
}
|
||||
|
||||
private static List<Point> asList(Point first, Point second, Point third, Point fourth, final Point... others) {
|
||||
|
||||
ArrayList<Point> result = new ArrayList<Point>(3 + others.length);
|
||||
|
||||
result.add(first);
|
||||
result.add(second);
|
||||
result.add(third);
|
||||
result.add(fourth);
|
||||
result.addAll(Arrays.asList(others));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -28,6 +28,7 @@ import java.lang.annotation.Target;
|
||||
* @author Oliver Gierke
|
||||
* @author Philipp Schneider
|
||||
* @author Johno Crawford
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Documented
|
||||
@@ -105,9 +106,9 @@ public @interface CompoundIndex {
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* db.root.ensureIndex( { hybrid.h1: 1, hybrid.h2: 1 } , { name: "hybrid.compound_index" } )
|
||||
* db.root.ensureIndex( { nested.n1: 1, nested.n2: 1 } , { name: "nested.compound_index" } )
|
||||
* db.hybrid.ensureIndex( { h1: 1, h2: 1 } , { name: "compound_index" } )
|
||||
* db.root.createIndex( { hybrid.h1: 1, hybrid.h2: 1 } , { name: "hybrid.compound_index" } )
|
||||
* db.root.createIndex( { nested.n1: 1, nested.n2: 1 } , { name: "nested.compound_index" } )
|
||||
* db.hybrid.createIndex( { h1: 1, h2: 1 } , { name: "compound_index" } )
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -26,6 +26,7 @@ import java.lang.annotation.Target;
|
||||
* @author Jon Brisbin
|
||||
* @author Laurent Canet
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -62,9 +63,9 @@ public @interface GeoSpatialIndexed {
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* db.root.ensureIndex( { hybrid.h1: "2d" } , { name: "hybrid.index" } )
|
||||
* db.root.ensureIndex( { nested.n1: "2d" } , { name: "nested.index" } )
|
||||
* db.hybrid.ensureIndex( { h1: "2d" } , { name: "index" } )
|
||||
* db.root.createIndex( { hybrid.h1: "2d" } , { name: "hybrid.index" } )
|
||||
* db.root.createIndex( { nested.n1: "2d" } , { name: "nested.index" } )
|
||||
* db.hybrid.createIndex( { h1: "2d" } , { name: "index" } )
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.index;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
@@ -44,7 +45,7 @@ public class Index implements IndexDefinition {
|
||||
*
|
||||
* @deprecated since 1.7.
|
||||
*/
|
||||
@Deprecated//
|
||||
@Deprecated //
|
||||
DROP
|
||||
}
|
||||
|
||||
@@ -175,11 +176,18 @@ public class Index implements IndexDefinition {
|
||||
return unique();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexKeys()
|
||||
*/
|
||||
public DBObject getIndexKeys() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
for (String k : fieldSpec.keySet()) {
|
||||
dbo.put(k, fieldSpec.get(k).equals(Direction.ASC) ? 1 : -1);
|
||||
|
||||
for (Entry<String, Direction> entry : fieldSpec.entrySet()) {
|
||||
dbo.put(entry.getKey(), Direction.ASC.equals(entry.getValue()) ? 1 : -1);
|
||||
}
|
||||
|
||||
return dbo;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -16,22 +16,24 @@
|
||||
package org.springframework.data.mongodb.core.index;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* {@link IndexResolver} finds those {@link IndexDefinition}s to be created for a given class.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
interface IndexResolver {
|
||||
|
||||
/**
|
||||
* Find and create {@link IndexDefinition}s for properties of given {@code type}. {@link IndexDefinition}s are created
|
||||
* Find and create {@link IndexDefinition}s for properties of given {@link TypeInformation}. {@link IndexDefinition}s are created
|
||||
* for properties and types with {@link Indexed}, {@link CompoundIndexes} or {@link GeoSpatialIndexed}.
|
||||
*
|
||||
* @param type
|
||||
* @param typeInformation
|
||||
* @return Empty {@link Iterable} in case no {@link IndexDefinition} could be resolved for type.
|
||||
*/
|
||||
Iterable<? extends IndexDefinitionHolder> resolveIndexForClass(Class<?> type);
|
||||
Iterable<? extends IndexDefinitionHolder> resolveIndexFor(TypeInformation<?> typeInformation);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -28,6 +28,7 @@ import java.lang.annotation.Target;
|
||||
* @author Philipp Schneider
|
||||
* @author Johno Crawford
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -88,9 +89,9 @@ public @interface Indexed {
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* db.root.ensureIndex( { hybrid.h1: 1 } , { name: "hybrid.index" } )
|
||||
* db.root.ensureIndex( { nested.n1: 1 } , { name: "nested.index" } )
|
||||
* db.hybrid.ensureIndex( { h1: 1} , { name: "index" } )
|
||||
* db.root.createIndex( { hybrid.h1: 1 } , { name: "hybrid.index" } )
|
||||
* db.root.createIndex( { nested.n1: 1 } , { name: "nested.index" } )
|
||||
* db.hybrid.createIndex( { h1: 1} , { name: "index" } )
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -60,4 +60,10 @@ public class MongoMappingEventPublisher implements ApplicationEventPublisher {
|
||||
indexCreator.onApplicationEvent((MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>) event);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationEventPublisher#publishEvent(java.lang.Object)
|
||||
*/
|
||||
public void publishEvent(Object event) {}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -29,7 +29,6 @@ import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexRes
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -43,8 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @author Laurent Canet
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoPersistentEntityIndexCreator implements
|
||||
ApplicationListener<MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
||||
public class MongoPersistentEntityIndexCreator implements ApplicationListener<MappingContextEvent<?, ?>> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MongoPersistentEntityIndexCreator.class);
|
||||
|
||||
@@ -54,7 +52,7 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
private final IndexResolver indexResolver;
|
||||
|
||||
/**
|
||||
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||
* Creates a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||
* {@link MongoDbFactory}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
@@ -65,7 +63,7 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Creats a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||
* Creates a new {@link MongoPersistentEntityIndexCreator} for the given {@link MongoMappingContext} and
|
||||
* {@link MongoDbFactory}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
@@ -92,7 +90,7 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(MappingContextEvent<MongoPersistentEntity<?>, MongoPersistentProperty> event) {
|
||||
public void onApplicationEvent(MappingContextEvent<?, ?> event) {
|
||||
|
||||
if (!event.wasEmittedBy(mappingContext)) {
|
||||
return;
|
||||
@@ -102,7 +100,7 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
|
||||
// Double check type as Spring infrastructure does not consider nested generics
|
||||
if (entity instanceof MongoPersistentEntity) {
|
||||
checkForIndexes(event.getPersistentEntity());
|
||||
checkForIndexes((MongoPersistentEntity<?>) entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,15 +123,15 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
private void checkForAndCreateIndexes(MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (entity.findAnnotation(Document.class) != null) {
|
||||
for (IndexDefinitionHolder indexToCreate : indexResolver.resolveIndexForClass(entity.getType())) {
|
||||
for (IndexDefinitionHolder indexToCreate : indexResolver.resolveIndexFor(entity.getTypeInformation())) {
|
||||
createIndex(indexToCreate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createIndex(IndexDefinitionHolder indexDefinition) {
|
||||
mongoDbFactory.getDb().getCollection(indexDefinition.getCollection())
|
||||
.createIndex(indexDefinition.getIndexKeys(), indexDefinition.getIndexOptions());
|
||||
mongoDbFactory.getDb().getCollection(indexDefinition.getCollection()).createIndex(indexDefinition.getIndexKeys(),
|
||||
indexDefinition.getIndexOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -27,7 +27,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mongodb.core.index.Index.Duplicates;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.TextIndexIncludeOptions.IncludeStrategy;
|
||||
import org.springframework.data.mongodb.core.index.TextIndexDefinition.TextIndexDefinitionBuilder;
|
||||
@@ -36,6 +39,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -51,6 +55,7 @@ import com.mongodb.util.JSON;
|
||||
* scanning related annotations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
@@ -70,13 +75,12 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexResolver#resolveIndexForClass(java.lang.Class)
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexResolver#resolveIndexForClass(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
public List<IndexDefinitionHolder> resolveIndexForClass(Class<?> type) {
|
||||
return resolveIndexForEntity(mappingContext.getPersistentEntity(type));
|
||||
public Iterable<? extends IndexDefinitionHolder> resolveIndexFor(TypeInformation<?> typeInformation) {
|
||||
return resolveIndexForEntity(mappingContext.getPersistentEntity(typeInformation));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +111,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
try {
|
||||
if (persistentProperty.isEntity()) {
|
||||
indexInformation.addAll(resolveIndexForClass(persistentProperty.getActualType(),
|
||||
indexInformation.addAll(resolveIndexForClass(persistentProperty.getTypeInformation().getActualType(),
|
||||
persistentProperty.getFieldName(), root.getCollection(), guard));
|
||||
}
|
||||
|
||||
@@ -117,11 +121,13 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexInformation.add(indexDefinitionHolder);
|
||||
}
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
indexInformation.addAll(resolveIndexesForDbrefs("", root.getCollection(), root));
|
||||
|
||||
return indexInformation;
|
||||
}
|
||||
|
||||
@@ -134,7 +140,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
* @return List of {@link IndexDefinitionHolder} representing indexes for given type and its referenced property
|
||||
* types. Will never be {@code null}.
|
||||
*/
|
||||
private List<IndexDefinitionHolder> resolveIndexForClass(final Class<?> type, final String path,
|
||||
private List<IndexDefinitionHolder> resolveIndexForClass(final TypeInformation<?> type, final String path,
|
||||
final String collection, final CycleGuard guard) {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
|
||||
@@ -152,10 +158,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
if (persistentProperty.isEntity()) {
|
||||
try {
|
||||
indexInformation.addAll(resolveIndexForClass(persistentProperty.getActualType(), propertyDotPath,
|
||||
collection, guard));
|
||||
indexInformation.addAll(resolveIndexForClass(persistentProperty.getTypeInformation().getActualType(),
|
||||
propertyDotPath, collection, guard));
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +173,8 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
}
|
||||
});
|
||||
|
||||
indexInformation.addAll(resolveIndexesForDbrefs(path, collection, entity));
|
||||
|
||||
return indexInformation;
|
||||
}
|
||||
|
||||
@@ -192,20 +200,21 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
return createCompoundIndexDefinitions(dotPath, collection, entity);
|
||||
}
|
||||
|
||||
private Collection<? extends IndexDefinitionHolder> potentiallyCreateTextIndexDefinition(MongoPersistentEntity<?> root) {
|
||||
private Collection<? extends IndexDefinitionHolder> potentiallyCreateTextIndexDefinition(
|
||||
MongoPersistentEntity<?> root) {
|
||||
|
||||
TextIndexDefinitionBuilder indexDefinitionBuilder = new TextIndexDefinitionBuilder().named(root.getType()
|
||||
.getSimpleName() + "_TextIndex");
|
||||
TextIndexDefinitionBuilder indexDefinitionBuilder = new TextIndexDefinitionBuilder()
|
||||
.named(root.getType().getSimpleName() + "_TextIndex");
|
||||
|
||||
if (StringUtils.hasText(root.getLanguage())) {
|
||||
indexDefinitionBuilder.withDefaultLanguage(root.getLanguage());
|
||||
}
|
||||
|
||||
try {
|
||||
appendTextIndexInformation("", indexDefinitionBuilder, root,
|
||||
new TextIndexIncludeOptions(IncludeStrategy.DEFAULT), new CycleGuard());
|
||||
appendTextIndexInformation("", indexDefinitionBuilder, root, new TextIndexIncludeOptions(IncludeStrategy.DEFAULT),
|
||||
new CycleGuard());
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
|
||||
TextIndexDefinition indexDefinition = indexDefinitionBuilder.build();
|
||||
@@ -219,9 +228,8 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
}
|
||||
|
||||
private void appendTextIndexInformation(final String dotPath,
|
||||
final TextIndexDefinitionBuilder indexDefinitionBuilder, final MongoPersistentEntity<?> entity,
|
||||
final TextIndexIncludeOptions includeOptions, final CycleGuard guard) {
|
||||
private void appendTextIndexInformation(final String dotPath, final TextIndexDefinitionBuilder indexDefinitionBuilder,
|
||||
final MongoPersistentEntity<?> entity, final TextIndexIncludeOptions includeOptions, final CycleGuard guard) {
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
|
||||
@@ -248,19 +256,18 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
TextIndexIncludeOptions optionsForNestedType = includeOptions;
|
||||
if (!IncludeStrategy.FORCE.equals(includeOptions.getStrategy()) && indexed != null) {
|
||||
optionsForNestedType = new TextIndexIncludeOptions(IncludeStrategy.FORCE, new TextIndexedFieldSpec(
|
||||
propertyDotPath, weight));
|
||||
optionsForNestedType = new TextIndexIncludeOptions(IncludeStrategy.FORCE,
|
||||
new TextIndexedFieldSpec(propertyDotPath, weight));
|
||||
}
|
||||
|
||||
try {
|
||||
appendTextIndexInformation(propertyDotPath, indexDefinitionBuilder,
|
||||
mappingContext.getPersistentEntity(persistentProperty.getActualType()), optionsForNestedType, guard);
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
LOGGER.info(e.getMessage(), e);
|
||||
} catch (InvalidDataAccessApiUsageException e) {
|
||||
LOGGER.warn(
|
||||
String.format("Potentially invald index structure discovered. Breaking operation for %s.",
|
||||
entity.getName()), e);
|
||||
LOGGER.info(String.format("Potentially invalid index structure discovered. Breaking operation for %s.",
|
||||
entity.getName()), e);
|
||||
}
|
||||
} else if (includeOptions.isForce() || indexed != null) {
|
||||
indexDefinitionBuilder.onField(propertyDotPath, weight);
|
||||
@@ -305,8 +312,8 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
protected IndexDefinitionHolder createCompoundIndexDefinition(String dotPath, String fallbackCollection,
|
||||
CompoundIndex index, MongoPersistentEntity<?> entity) {
|
||||
|
||||
CompoundIndexDefinition indexDefinition = new CompoundIndexDefinition(resolveCompoundIndexKeyFromStringDefinition(
|
||||
dotPath, index.def()));
|
||||
CompoundIndexDefinition indexDefinition = new CompoundIndexDefinition(
|
||||
resolveCompoundIndexKeyFromStringDefinition(dotPath, index.def()));
|
||||
|
||||
if (!index.useGeneratedName()) {
|
||||
indexDefinition.named(pathAwareIndexName(index.name(), dotPath, null));
|
||||
@@ -430,13 +437,45 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
if (StringUtils.hasText(dotPath)) {
|
||||
|
||||
nameToUse = StringUtils.hasText(nameToUse) ? (property != null ? dotPath.replace("." + property.getFieldName(),
|
||||
"") : dotPath) + "." + nameToUse : dotPath;
|
||||
nameToUse = StringUtils.hasText(nameToUse)
|
||||
? (property != null ? dotPath.replace("." + property.getFieldName(), "") : dotPath) + "." + nameToUse
|
||||
: dotPath;
|
||||
}
|
||||
return nameToUse;
|
||||
|
||||
}
|
||||
|
||||
private List<IndexDefinitionHolder> resolveIndexesForDbrefs(final String path, final String collection,
|
||||
MongoPersistentEntity<?> entity) {
|
||||
|
||||
final List<IndexDefinitionHolder> indexes = new ArrayList<IndexDefinitionHolder>(0);
|
||||
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||
|
||||
MongoPersistentProperty property = association.getInverse();
|
||||
|
||||
String propertyDotPath = (StringUtils.hasText(path) ? path + "." : "") + property.getFieldName();
|
||||
|
||||
if (property.isAnnotationPresent(GeoSpatialIndexed.class) || property.isAnnotationPresent(TextIndexed.class)) {
|
||||
throw new MappingException(
|
||||
String.format("Cannot create geospatial-/text- index on DBRef in collection '%s' for path '%s'.",
|
||||
collection, propertyDotPath));
|
||||
}
|
||||
|
||||
IndexDefinitionHolder indexDefinitionHolder = createIndexDefinitionHolderForProperty(propertyDotPath,
|
||||
collection, property);
|
||||
|
||||
if (indexDefinitionHolder != null) {
|
||||
indexes.add(indexDefinitionHolder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CycleGuard} holds information about properties and the paths for accessing those. This information is used
|
||||
* to detect potential cycles within the references.
|
||||
@@ -466,8 +505,9 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
for (Path existingPath : paths) {
|
||||
|
||||
if (existingPath.cycles(property, path)) {
|
||||
if (existingPath.cycles(property, path) && property.isEntity()) {
|
||||
paths.add(new Path(property, path));
|
||||
|
||||
throw new CyclicPropertyReferenceException(property.getFieldName(), property.getOwner().getType(),
|
||||
existingPath.getPath());
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -305,28 +306,44 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
*/
|
||||
private static class PropertyTypeAssertionHandler implements PropertyHandler<MongoPersistentProperty> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PropertyHandler#doWithPersistentProperty(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
potentiallyAssertTextScoreType(persistentProperty);
|
||||
potentiallyAssertLanguageType(persistentProperty);
|
||||
potentiallyAssertDBRefTargetType(persistentProperty);
|
||||
}
|
||||
|
||||
private void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) {
|
||||
private static void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isExplicitLanguageProperty()) {
|
||||
assertPropertyType(persistentProperty, String.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) {
|
||||
private static void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isTextScoreProperty()) {
|
||||
assertPropertyType(persistentProperty, Float.class, Double.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertPropertyType(MongoPersistentProperty persistentProperty, Class<?>... validMatches) {
|
||||
private static void potentiallyAssertDBRefTargetType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isDbReference() && persistentProperty.getDBRef().lazy()) {
|
||||
if (persistentProperty.isArray() || Modifier.isFinal(persistentProperty.getActualType().getModifiers())) {
|
||||
throw new MappingException(String.format(
|
||||
"Invalid lazy DBRef property for %s. Found %s which must not be an array nor a final class.",
|
||||
persistentProperty.getField(), persistentProperty.getActualType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertPropertyType(MongoPersistentProperty persistentProperty, Class<?>... validMatches) {
|
||||
|
||||
for (Class<?> potentialMatch : validMatches) {
|
||||
if (ClassUtils.isAssignable(potentialMatch, persistentProperty.getActualType())) {
|
||||
@@ -334,10 +351,9 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
}
|
||||
}
|
||||
|
||||
throw new MappingException(String.format("Missmatching types for %s. Found %s expected one of %s.",
|
||||
persistentProperty.getField(), persistentProperty.getActualType(),
|
||||
StringUtils.arrayToCommaDelimitedString(validMatches)));
|
||||
throw new MappingException(
|
||||
String.format("Missmatching types for %s. Found %s expected one of %s.", persistentProperty.getField(),
|
||||
persistentProperty.getActualType(), StringUtils.arrayToCommaDelimitedString(validMatches)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -31,6 +31,8 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
|
||||
private Boolean isIdProperty;
|
||||
private Boolean isAssociation;
|
||||
private String fieldName;
|
||||
private Boolean usePropertyAccess;
|
||||
private Boolean isTransient;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CachingMongoPersistentProperty}.
|
||||
@@ -85,4 +87,32 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
|
||||
|
||||
return this.fieldName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#usePropertyAccess()
|
||||
*/
|
||||
@Override
|
||||
public boolean usePropertyAccess() {
|
||||
|
||||
if (this.usePropertyAccess == null) {
|
||||
this.usePropertyAccess = super.usePropertyAccess();
|
||||
}
|
||||
|
||||
return this.usePropertyAccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isTransient()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
|
||||
if (this.isTransient == null) {
|
||||
this.isTransient = super.isTransient();
|
||||
}
|
||||
|
||||
return this.isTransient;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
|
||||
int getFieldOrder();
|
||||
|
||||
/**
|
||||
* Returns whether the propert is a {@link com.mongodb.DBRef}. If this returns {@literal true} you can expect
|
||||
* Returns whether the property is a {@link com.mongodb.DBRef}. If this returns {@literal true} you can expect
|
||||
* {@link #getDBRef()} to return an non-{@literal null} value.
|
||||
*
|
||||
* @return
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -22,6 +22,11 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MapReduceCommand;
|
||||
|
||||
/**
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MapReduceOptions {
|
||||
|
||||
private String outputCollection;
|
||||
@@ -40,6 +45,8 @@ public class MapReduceOptions {
|
||||
|
||||
private Boolean verbose = true;
|
||||
|
||||
private Integer limit;
|
||||
|
||||
private Map<String, Object> extraOptions = new HashMap<String, Object>();
|
||||
|
||||
/**
|
||||
@@ -59,6 +66,8 @@ public class MapReduceOptions {
|
||||
* @return MapReduceOptions so that methods can be chained in a fluent API style
|
||||
*/
|
||||
public MapReduceOptions limit(int limit) {
|
||||
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -197,12 +206,19 @@ public class MapReduceOptions {
|
||||
* @param key The key option
|
||||
* @param value The value of the option
|
||||
* @return MapReduceOptions so that methods can be chained in a fluent API style
|
||||
* @deprecated since 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
public MapReduceOptions extraOption(String key, Object value) {
|
||||
extraOptions.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated since 1.7
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, Object> getExtraOptions() {
|
||||
return extraOptions;
|
||||
}
|
||||
@@ -235,6 +251,15 @@ public class MapReduceOptions {
|
||||
return this.scopeVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of documents for the input into the map function.
|
||||
*
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
public Integer getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public DBObject getOptionsObject() {
|
||||
BasicDBObject cmd = new BasicDBObject();
|
||||
|
||||
@@ -252,6 +277,10 @@ public class MapReduceOptions {
|
||||
cmd.put("scope", scopeVariables);
|
||||
}
|
||||
|
||||
if (limit != null) {
|
||||
cmd.put("limit", limit);
|
||||
}
|
||||
|
||||
if (!extraOptions.keySet().isEmpty()) {
|
||||
cmd.putAll(extraOptions);
|
||||
}
|
||||
@@ -263,18 +292,18 @@ public class MapReduceOptions {
|
||||
BasicDBObject out = new BasicDBObject();
|
||||
|
||||
switch (outputType) {
|
||||
case INLINE:
|
||||
out.put("inline", 1);
|
||||
break;
|
||||
case REPLACE:
|
||||
out.put("replace", outputCollection);
|
||||
break;
|
||||
case MERGE:
|
||||
out.put("merge", outputCollection);
|
||||
break;
|
||||
case REDUCE:
|
||||
out.put("reduce", outputCollection);
|
||||
break;
|
||||
case INLINE:
|
||||
out.put("inline", 1);
|
||||
break;
|
||||
case REPLACE:
|
||||
out.put("replace", outputCollection);
|
||||
break;
|
||||
case MERGE:
|
||||
out.put("merge", outputCollection);
|
||||
break;
|
||||
case REDUCE:
|
||||
out.put("reduce", outputCollection);
|
||||
break;
|
||||
}
|
||||
|
||||
if (outputDatabase != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -21,12 +21,14 @@ import java.util.List;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MapReduceOutput;
|
||||
|
||||
/**
|
||||
* Collects the results of performing a MapReduce operations.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @param <T> The class in which the results are mapped onto, accessible via an iterator.
|
||||
*/
|
||||
public class MapReduceResults<T> implements Iterable<T> {
|
||||
@@ -42,7 +44,9 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
*
|
||||
* @param mappedResults must not be {@literal null}.
|
||||
* @param rawResults must not be {@literal null}.
|
||||
* @deprecated since 1.7. Please use {@link #MapReduceResults(List, MapReduceOutput)}
|
||||
*/
|
||||
@Deprecated
|
||||
public MapReduceResults(List<T> mappedResults, DBObject rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
@@ -55,6 +59,25 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
this.outputCollection = parseOutputCollection(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MapReduceResults} from the given mapped results and the {@link MapReduceOutput}.
|
||||
*
|
||||
* @param mappedResults must not be {@literal null}.
|
||||
* @param mapReduceOutput must not be {@literal null}.
|
||||
* @since 1.7
|
||||
*/
|
||||
public MapReduceResults(List<T> mappedResults, MapReduceOutput mapReduceOutput) {
|
||||
|
||||
Assert.notNull(mappedResults, "MappedResults must not be null!");
|
||||
Assert.notNull(mapReduceOutput, "MapReduceOutput must not be null!");
|
||||
|
||||
this.mappedResults = mappedResults;
|
||||
this.rawResults = null;
|
||||
this.mapReduceTiming = parseTiming(mapReduceOutput);
|
||||
this.mapReduceCounts = parseCounts(mapReduceOutput);
|
||||
this.outputCollection = parseOutputCollection(mapReduceOutput);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
@@ -79,7 +102,7 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
return rawResults;
|
||||
}
|
||||
|
||||
private MapReduceTiming parseTiming(DBObject rawResults) {
|
||||
private static MapReduceTiming parseTiming(DBObject rawResults) {
|
||||
|
||||
DBObject timing = (DBObject) rawResults.get("timing");
|
||||
|
||||
@@ -102,8 +125,10 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private Long getAsLong(DBObject source, String key) {
|
||||
private static Long getAsLong(DBObject source, String key) {
|
||||
|
||||
Object raw = source.get(key);
|
||||
|
||||
return raw instanceof Long ? (Long) raw : (Integer) raw;
|
||||
}
|
||||
|
||||
@@ -113,7 +138,7 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
* @param rawResults
|
||||
* @return
|
||||
*/
|
||||
private MapReduceCounts parseCounts(DBObject rawResults) {
|
||||
private static MapReduceCounts parseCounts(DBObject rawResults) {
|
||||
|
||||
DBObject counts = (DBObject) rawResults.get("counts");
|
||||
|
||||
@@ -134,7 +159,7 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
* @param rawResults
|
||||
* @return
|
||||
*/
|
||||
private String parseOutputCollection(DBObject rawResults) {
|
||||
private static String parseOutputCollection(DBObject rawResults) {
|
||||
|
||||
Object resultField = rawResults.get("result");
|
||||
|
||||
@@ -145,4 +170,17 @@ public class MapReduceResults<T> implements Iterable<T> {
|
||||
return resultField instanceof DBObject ? ((DBObject) resultField).get("collection").toString() : resultField
|
||||
.toString();
|
||||
}
|
||||
|
||||
private static MapReduceCounts parseCounts(final MapReduceOutput mapReduceOutput) {
|
||||
return new MapReduceCounts(mapReduceOutput.getInputCount(), mapReduceOutput.getEmitCount(),
|
||||
mapReduceOutput.getOutputCount());
|
||||
}
|
||||
|
||||
private static String parseOutputCollection(final MapReduceOutput mapReduceOutput) {
|
||||
return mapReduceOutput.getCollectionName();
|
||||
}
|
||||
|
||||
private static MapReduceTiming parseTiming(MapReduceOutput mapReduceOutput) {
|
||||
return new MapReduceTiming(-1, -1, mapReduceOutput.getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -17,13 +17,10 @@ package org.springframework.data.mongodb.core.mapreduce;
|
||||
|
||||
public class MapReduceTiming {
|
||||
|
||||
private long mapTime;
|
||||
|
||||
private long emitLoopTime;
|
||||
|
||||
private long totalTime;
|
||||
private long mapTime, emitLoopTime, totalTime;
|
||||
|
||||
public MapReduceTiming(long mapTime, long emitLoopTime, long totalTime) {
|
||||
|
||||
this.mapTime = mapTime;
|
||||
this.emitLoopTime = emitLoopTime;
|
||||
this.totalTime = totalTime;
|
||||
@@ -41,37 +38,52 @@ public class MapReduceTiming {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MapReduceTiming [mapTime=" + mapTime + ", emitLoopTime=" + emitLoopTime + ", totalTime=" + totalTime + "]";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
result = prime * result + (int) (emitLoopTime ^ (emitLoopTime >>> 32));
|
||||
result = prime * result + (int) (mapTime ^ (mapTime >>> 32));
|
||||
result = prime * result + (int) (totalTime ^ (totalTime >>> 32));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
MapReduceTiming other = (MapReduceTiming) obj;
|
||||
if (emitLoopTime != other.emitLoopTime)
|
||||
return false;
|
||||
if (mapTime != other.mapTime)
|
||||
return false;
|
||||
if (totalTime != other.totalTime)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof MapReduceTiming)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MapReduceTiming that = (MapReduceTiming) obj;
|
||||
|
||||
return this.emitLoopTime == that.emitLoopTime && //
|
||||
this.mapTime == that.mapTime && //
|
||||
this.totalTime == that.totalTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import com.mongodb.util.JSON;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author John Willemin
|
||||
*/
|
||||
public class BasicQuery extends Query {
|
||||
|
||||
@@ -70,6 +71,19 @@ public class BasicQuery extends Query {
|
||||
|
||||
@Override
|
||||
public DBObject getFieldsObject() {
|
||||
|
||||
if (fieldsObject == null) {
|
||||
return super.getFieldsObject();
|
||||
}
|
||||
|
||||
if (super.getFieldsObject() != null) {
|
||||
|
||||
DBObject combinedFieldsObject = new BasicDBObject();
|
||||
combinedFieldsObject.putAll(fieldsObject);
|
||||
combinedFieldsObject.putAll(super.getFieldsObject());
|
||||
return combinedFieldsObject;
|
||||
}
|
||||
|
||||
return fieldsObject;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.query;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -87,12 +88,8 @@ public class BasicUpdate extends Update {
|
||||
|
||||
@Override
|
||||
public Update pullAll(String key, Object[] values) {
|
||||
Object[] convertedValues = new Object[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
convertedValues[i] = values[i];
|
||||
}
|
||||
DBObject keyValue = new BasicDBObject();
|
||||
keyValue.put(key, convertedValues);
|
||||
keyValue.put(key, Arrays.copyOf(values, values.length));
|
||||
updateObject.put("$pullAll", keyValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bson.BSON;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJson;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -117,7 +119,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
|
||||
private boolean lastOperatorWasNot() {
|
||||
return this.criteria.size() > 0 && "$not".equals(this.criteria.keySet().toArray()[this.criteria.size() - 1]);
|
||||
return !this.criteria.isEmpty() && "$not".equals(this.criteria.keySet().toArray()[this.criteria.size() - 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,8 +378,8 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $within $centerSphere} operation. This is only available for Mongo
|
||||
* 1.7 and higher.
|
||||
* Creates a geospatial criterion using a {@literal $geoWithin $centerSphere} operation. This is only available for
|
||||
* Mongo 2.4 and higher.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/centerSphere/
|
||||
@@ -386,12 +388,12 @@ public class Criteria implements CriteriaDefinition {
|
||||
*/
|
||||
public Criteria withinSphere(Circle circle) {
|
||||
Assert.notNull(circle);
|
||||
criteria.put("$within", new GeoCommand(new Sphere(circle)));
|
||||
criteria.put("$geoWithin", new GeoCommand(new Sphere(circle)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $within} operation.
|
||||
* Creates a geospatial criterion using a {@literal $geoWithin} operation.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/query/geoWithin/
|
||||
* @param shape
|
||||
@@ -400,7 +402,7 @@ public class Criteria implements CriteriaDefinition {
|
||||
public Criteria within(Shape shape) {
|
||||
|
||||
Assert.notNull(shape);
|
||||
criteria.put("$within", new GeoCommand(shape));
|
||||
criteria.put("$geoWithin", new GeoCommand(shape));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -439,10 +441,35 @@ public class Criteria implements CriteriaDefinition {
|
||||
* @return
|
||||
*/
|
||||
public Criteria maxDistance(double maxDistance) {
|
||||
|
||||
if (createNearCriteriaForCommand("$near", "$maxDistance", maxDistance)
|
||||
|| createNearCriteriaForCommand("$nearSphere", "$maxDistance", maxDistance)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
criteria.put("$maxDistance", maxDistance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $minDistance} operation, for use with {@literal $near} or
|
||||
* {@literal $nearSphere}.
|
||||
*
|
||||
* @param minDistance
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public Criteria minDistance(double minDistance) {
|
||||
|
||||
if (createNearCriteriaForCommand("$near", "$minDistance", minDistance)
|
||||
|| createNearCriteriaForCommand("$nearSphere", "$minDistance", minDistance)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
criteria.put("$minDistance", minDistance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a criterion using the {@literal $elemMatch} operator
|
||||
*
|
||||
@@ -539,18 +566,25 @@ public class Criteria implements CriteriaDefinition {
|
||||
DBObject dbo = new BasicDBObject();
|
||||
boolean not = false;
|
||||
|
||||
for (String k : this.criteria.keySet()) {
|
||||
Object value = this.criteria.get(k);
|
||||
for (Entry<String, Object> entry : criteria.entrySet()) {
|
||||
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
if (requiresGeoJsonFormat(value)) {
|
||||
value = new BasicDBObject("$geometry", value);
|
||||
}
|
||||
|
||||
if (not) {
|
||||
DBObject notDbo = new BasicDBObject();
|
||||
notDbo.put(k, value);
|
||||
notDbo.put(key, value);
|
||||
dbo.put("$not", notDbo);
|
||||
not = false;
|
||||
} else {
|
||||
if ("$not".equals(k) && value == null) {
|
||||
if ("$not".equals(key) && value == null) {
|
||||
not = true;
|
||||
} else {
|
||||
dbo.put(k, value);
|
||||
dbo.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -593,6 +627,31 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean createNearCriteriaForCommand(String command, String operation, double maxDistance) {
|
||||
|
||||
if (!criteria.containsKey(command)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object existingNearOperationValue = criteria.get(command);
|
||||
|
||||
if (existingNearOperationValue instanceof DBObject) {
|
||||
|
||||
((DBObject) existingNearOperationValue).put(operation, maxDistance);
|
||||
|
||||
return true;
|
||||
|
||||
} else if (existingNearOperationValue instanceof GeoJson) {
|
||||
|
||||
BasicDBObject dbo = new BasicDBObject("$geometry", existingNearOperationValue).append(operation, maxDistance);
|
||||
criteria.put(command, dbo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
@@ -671,4 +730,9 @@ public class Criteria implements CriteriaDefinition {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean requiresGeoJsonFormat(Object value) {
|
||||
return value instanceof GeoJson
|
||||
|| (value instanceof GeoCommand && ((GeoCommand) value).getShape() instanceof GeoJson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -83,14 +83,10 @@ public class Field {
|
||||
|
||||
public DBObject getFieldsObject() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
DBObject dbo = new BasicDBObject(criteria);
|
||||
|
||||
for (String k : criteria.keySet()) {
|
||||
dbo.put(k, criteria.get(k));
|
||||
}
|
||||
|
||||
for (String k : slices.keySet()) {
|
||||
dbo.put(k, new BasicDBObject("$slice", slices.get(k)));
|
||||
for (Entry<String, Object> entry : slices.entrySet()) {
|
||||
dbo.put(entry.getKey(), new BasicDBObject("$slice", entry.getValue()));
|
||||
}
|
||||
|
||||
for (Entry<String, Criteria> entry : elemMatchs.entrySet()) {
|
||||
@@ -134,8 +130,8 @@ public class Field {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean samePositionKey = this.postionKey == null ? that.postionKey == null : this.postionKey
|
||||
.equals(that.postionKey);
|
||||
boolean samePositionKey = this.postionKey == null ? that.postionKey == null
|
||||
: this.postionKey.equals(that.postionKey);
|
||||
boolean samePositionValue = this.positionValue == that.positionValue;
|
||||
|
||||
return samePositionKey && samePositionValue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.query;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Polygon;
|
||||
@@ -26,9 +28,10 @@ import org.springframework.util.Assert;
|
||||
* Wrapper around a {@link Shape} to allow appropriate query rendering.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
public class GeoCommand {
|
||||
public final class GeoCommand {
|
||||
|
||||
private final Shape shape;
|
||||
private final String command;
|
||||
@@ -82,4 +85,39 @@ public class GeoCommand {
|
||||
|
||||
throw new IllegalArgumentException("Unknown shape: " + shape);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 31;
|
||||
|
||||
result += 17 * nullSafeHashCode(this.command);
|
||||
result += 17 * nullSafeHashCode(this.shape);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof GeoCommand)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GeoCommand that = (GeoCommand) obj;
|
||||
|
||||
return nullSafeEquals(this.command, that.command) && nullSafeEquals(this.shape, that.shape);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2015 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.
|
||||
@@ -40,6 +40,7 @@ public final class NearQuery {
|
||||
private final Point point;
|
||||
private Query query;
|
||||
private Distance maxDistance;
|
||||
private Distance minDistance;
|
||||
private Metric metric;
|
||||
private boolean spherical;
|
||||
private Integer num;
|
||||
@@ -211,6 +212,63 @@ public final class NearQuery {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum distance results shall have from the configured origin. If a {@link Metric} was set before the
|
||||
* given value will be interpreted as being a value in that metric. E.g.
|
||||
*
|
||||
* <pre>
|
||||
* NearQuery query = near(10.0, 20.0, Metrics.KILOMETERS).minDistance(150);
|
||||
* </pre>
|
||||
*
|
||||
* Will set the minimum distance to 150 kilometers.
|
||||
*
|
||||
* @param minDistance
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public NearQuery minDistance(double minDistance) {
|
||||
return minDistance(new Distance(minDistance, getMetric()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum distance supplied in a given metric. Will normalize the distance but not reconfigure the query's
|
||||
* result {@link Metric} if one was configured before.
|
||||
*
|
||||
* @param minDistance
|
||||
* @param metric must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public NearQuery minDistance(double minDistance, Metric metric) {
|
||||
|
||||
Assert.notNull(metric);
|
||||
return minDistance(new Distance(minDistance, metric));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum distance to the given {@link Distance}. Will set the returned {@link Metric} to be the one of the
|
||||
* given {@link Distance} if no {@link Metric} was set before.
|
||||
*
|
||||
* @param distance must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public NearQuery minDistance(Distance distance) {
|
||||
|
||||
Assert.notNull(distance);
|
||||
|
||||
if (distance.getMetric() != Metrics.NEUTRAL) {
|
||||
this.spherical(true);
|
||||
}
|
||||
|
||||
if (this.metric == null) {
|
||||
in(distance.getMetric());
|
||||
}
|
||||
|
||||
this.minDistance = distance;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum {@link Distance}.
|
||||
*
|
||||
@@ -220,6 +278,16 @@ public final class NearQuery {
|
||||
return this.maxDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum {@link Distance}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public Distance getMinDistance() {
|
||||
return this.minDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a {@link CustomMetric} with the given multiplier.
|
||||
*
|
||||
@@ -352,7 +420,11 @@ public final class NearQuery {
|
||||
}
|
||||
|
||||
if (maxDistance != null) {
|
||||
dbObject.put("maxDistance", this.maxDistance.getNormalizedValue());
|
||||
dbObject.put("maxDistance", maxDistance.getNormalizedValue());
|
||||
}
|
||||
|
||||
if (minDistance != null) {
|
||||
dbObject.put("minDistance", minDistance.getNormalizedValue());
|
||||
}
|
||||
|
||||
if (metric != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -94,9 +94,9 @@ public class Query {
|
||||
if (existing == null) {
|
||||
this.criteria.put(key, criteriaDefinition);
|
||||
} else {
|
||||
throw new InvalidMongoDbApiUsageException("Due to limitations of the com.mongodb.BasicDBObject, "
|
||||
+ "you can't add a second '" + key + "' criteria. " + "Query already contains '"
|
||||
+ existing.getCriteriaObject() + "'.");
|
||||
throw new InvalidMongoDbApiUsageException(
|
||||
"Due to limitations of the com.mongodb.BasicDBObject, " + "you can't add a second '" + key + "' criteria. "
|
||||
+ "Query already contains '" + existing.getCriteriaObject() + "'.");
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -176,7 +176,7 @@ public class Query {
|
||||
|
||||
for (Order order : sort) {
|
||||
if (order.isIgnoreCase()) {
|
||||
throw new IllegalArgumentException(String.format("Gven sort contained an Order for %s with ignore case! "
|
||||
throw new IllegalArgumentException(String.format("Given sort contained an Order for %s with ignore case! "
|
||||
+ "MongoDB does not support sorting ignoreing case currently!", order.getProperty()));
|
||||
}
|
||||
}
|
||||
@@ -221,10 +221,8 @@ public class Query {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
|
||||
for (String k : criteria.keySet()) {
|
||||
CriteriaDefinition c = criteria.get(k);
|
||||
DBObject cl = c.getCriteriaObject();
|
||||
dbo.putAll(cl);
|
||||
for (CriteriaDefinition definition : criteria.values()) {
|
||||
dbo.putAll(definition.getCriteriaObject());
|
||||
}
|
||||
|
||||
if (!restrictedTypes.isEmpty()) {
|
||||
|
||||
@@ -63,7 +63,7 @@ public class TextCriteria implements CriteriaDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* For a full list of supported languages see the mongdodb reference manual for <a
|
||||
* For a full list of supported languages see the mongodb reference manual for <a
|
||||
* href="http://docs.mongodb.org/manual/reference/text-search-languages/">Text Search Languages</a>.
|
||||
*
|
||||
* @param language
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2015 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.
|
||||
@@ -64,7 +64,7 @@ public class Update {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exlude fields from making
|
||||
* Creates an {@link Update} instance from the given {@link DBObject}. Allows to explicitly exclude fields from making
|
||||
* it into the created {@link Update} object. Note, that this will set attributes directly and <em>not</em> use
|
||||
* {@literal $set}. This means fields not given in the {@link DBObject} will be nulled when executing the update. To
|
||||
* create an only-updating {@link Update} instance of a {@link DBObject}, call {@link #set(String, Object)} for each
|
||||
@@ -190,12 +190,7 @@ public class Update {
|
||||
* @return
|
||||
*/
|
||||
public Update pushAll(String key, Object[] values) {
|
||||
|
||||
Object[] convertedValues = new Object[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
convertedValues[i] = values[i];
|
||||
}
|
||||
addMultiFieldOperation("$pushAll", key, convertedValues);
|
||||
addMultiFieldOperation("$pushAll", key, Arrays.copyOf(values, values.length));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -259,12 +254,7 @@ public class Update {
|
||||
* @return
|
||||
*/
|
||||
public Update pullAll(String key, Object[] values) {
|
||||
|
||||
Object[] convertedValues = new Object[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
convertedValues[i] = values[i];
|
||||
}
|
||||
addFieldOperation("$pullAll", key, convertedValues);
|
||||
addMultiFieldOperation("$pullAll", key, Arrays.copyOf(values, values.length));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -337,17 +327,22 @@ public class Update {
|
||||
}
|
||||
|
||||
public DBObject getUpdateObject() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
for (String k : modifierOps.keySet()) {
|
||||
dbo.put(k, modifierOps.get(k));
|
||||
}
|
||||
return dbo;
|
||||
return new BasicDBObject(modifierOps);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is not called anymore rather override {@link #addMultiFieldOperation(String, String, Object)}.
|
||||
*
|
||||
* @param operator
|
||||
* @param key
|
||||
* @param value
|
||||
* @deprectaed Use {@link #addMultiFieldOperation(String, String, Object)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void addFieldOperation(String operator, String key, Object value) {
|
||||
|
||||
Assert.hasText(key, "Key/Path for update must not be null or blank.");
|
||||
|
||||
modifierOps.put(operator, new BasicDBObject(key, value));
|
||||
this.keysToUpdate.add(key);
|
||||
}
|
||||
@@ -365,8 +360,8 @@ public class Update {
|
||||
if (existingValue instanceof BasicDBObject) {
|
||||
keyValueMap = (BasicDBObject) existingValue;
|
||||
} else {
|
||||
throw new InvalidDataAccessApiUsageException("Modifier Operations should be a LinkedHashMap but was "
|
||||
+ existingValue.getClass());
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Modifier Operations should be a LinkedHashMap but was " + existingValue.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,13 +518,7 @@ public class Update {
|
||||
return ((Collection<?>) values[0]).toArray();
|
||||
}
|
||||
|
||||
Object[] convertedValues = new Object[values.length];
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
convertedValues[i] = values[i];
|
||||
}
|
||||
|
||||
return convertedValues;
|
||||
return Arrays.copyOf(values, values.length);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.script;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object for MongoDB JavaScript functions implementation that can be saved or directly executed.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class ExecutableMongoScript {
|
||||
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* Creates new {@link ExecutableMongoScript}.
|
||||
*
|
||||
* @param code must not be {@literal null} or empty.
|
||||
*/
|
||||
public ExecutableMongoScript(String code) {
|
||||
|
||||
Assert.hasText(code, "Code must not be null or empty!");
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual script code.
|
||||
*
|
||||
* @return will never be {@literal null} or empty.
|
||||
*/
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.script;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link ExecutableMongoScript} assigned to a name that allows calling the function by its {@literal name} once it
|
||||
* has been saved to the {@link com.mongodb.DB} instance.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class NamedMongoScript {
|
||||
|
||||
private final @Id String name;
|
||||
private final ExecutableMongoScript script;
|
||||
|
||||
/**
|
||||
* Creates new {@link NamedMongoScript} that can be saved to the {@link com.mongodb.DB} instance.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param rawScript the {@link String} representation of the {@literal JavaScript} function. Must not be
|
||||
* {@literal null} or empty.
|
||||
*/
|
||||
public NamedMongoScript(String name, String rawScript) {
|
||||
this(name, new ExecutableMongoScript(rawScript));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link NamedMongoScript}.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param script must not be {@literal null}.
|
||||
*/
|
||||
public NamedMongoScript(String name, ExecutableMongoScript script) {
|
||||
|
||||
Assert.hasText(name, "Name must not be null or empty!");
|
||||
Assert.notNull(script, "ExecutableMongoScript must not be null!");
|
||||
|
||||
this.name = name;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual script code.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public String getCode() {
|
||||
return script.getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link ExecutableMongoScript}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public ExecutableMongoScript getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the script.
|
||||
*
|
||||
* @return will never be {@literal null} or empty.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -29,6 +29,7 @@ import com.mongodb.MongoException;
|
||||
* Base class to encapsulate common configuration settings when connecting to a database
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public abstract class AbstractMonitor {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -22,13 +22,14 @@ import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* Expose basic server information via JMX
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@ManagedResource(description = "Server Information")
|
||||
public class ServerInfo extends AbstractMonitor {
|
||||
@@ -37,20 +38,20 @@ public class ServerInfo extends AbstractMonitor {
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the used server reported by mongo.
|
||||
*
|
||||
* @return the reported hostname can also be an IP address.
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
/**
|
||||
* Returns the hostname of the used server reported by MongoDB.
|
||||
*
|
||||
* @return the reported hostname can also be an IP address.
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
@ManagedOperation(description = "Server host name")
|
||||
public String getHostName() throws UnknownHostException {
|
||||
|
||||
/*
|
||||
* UnknownHostException is not necessary anymore, but clients could have
|
||||
* called this method in a try..catch(UnknownHostException) already
|
||||
*/
|
||||
return getServerStatus().getServerUsed().getHost();
|
||||
|
||||
/*
|
||||
* UnknownHostException is not necessary anymore, but clients could have
|
||||
* called this method in a try..catch(UnknownHostException) already
|
||||
*/
|
||||
return mongo.getAddress().getHost();
|
||||
}
|
||||
|
||||
@ManagedMetric(displayName = "Uptime Estimate")
|
||||
@@ -72,5 +73,4 @@ public class ServerInfo extends AbstractMonitor {
|
||||
public double getUptime() {
|
||||
return (Double) getServerStatus().get("uptime");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.springframework.data.annotation.QueryAnnotation;
|
||||
public @interface Query {
|
||||
|
||||
/**
|
||||
* Takes a MongoDB JSON string to define the actual query to be executed. This one will take precendece over the
|
||||
* Takes a MongoDB JSON string to define the actual query to be executed. This one will take precedence over the
|
||||
* method name then.
|
||||
*
|
||||
* @return
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user