Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13823690fc | ||
|
|
fc0187eb8e | ||
|
|
07bf5a4f7e | ||
|
|
274adf320d | ||
|
|
aed983462f | ||
|
|
0f5179eb26 | ||
|
|
df40adb618 | ||
|
|
339d8e6f14 | ||
|
|
292e645387 | ||
|
|
df7c007e9e | ||
|
|
9f3465f63c | ||
|
|
2e7c166d38 | ||
|
|
ac7e3a708a | ||
|
|
fa50f74729 | ||
|
|
2aba831389 | ||
|
|
33c665fb98 | ||
|
|
55f83fa0f2 | ||
|
|
13f2472e2f | ||
|
|
5de9994093 | ||
|
|
4d24742181 | ||
|
|
4af876152c | ||
|
|
872e706d2a | ||
|
|
51c66723e9 | ||
|
|
ccfab5d91a | ||
|
|
c94c3f3791 | ||
|
|
4924ff54b6 | ||
|
|
edd9b58d1c | ||
|
|
dc6cbde842 | ||
|
|
aaaf7e57de | ||
|
|
76538aeff1 | ||
|
|
1181a21e51 | ||
|
|
c7f07d2386 | ||
|
|
054ad6fc12 | ||
|
|
1b4ecac732 | ||
|
|
1ef03bf707 | ||
|
|
a1febdb541 | ||
|
|
79fdf44d24 | ||
|
|
d8bb644b30 | ||
|
|
73db7b06b9 | ||
|
|
8483f36f48 | ||
|
|
b426bdd64a | ||
|
|
3349454a51 | ||
|
|
c04343a764 | ||
|
|
05311ea118 | ||
|
|
a18633f847 | ||
|
|
29e2f87ee1 | ||
|
|
5c5accd12d | ||
|
|
08e534adcd | ||
|
|
914acfea16 | ||
|
|
a6728f851b | ||
|
|
81a7515cb7 | ||
|
|
3f4087dc13 | ||
|
|
0430962861 | ||
|
|
8bb62a65db | ||
|
|
d6defbcb56 | ||
|
|
ed47850f71 | ||
|
|
ca1cfdf659 | ||
|
|
95d31d5bb7 | ||
|
|
a7c3ef2aa8 | ||
|
|
3320e49c0b | ||
|
|
286efca52d | ||
|
|
92926befc9 | ||
|
|
703f24ae1c | ||
|
|
febe703954 | ||
|
|
440d16ebc6 | ||
|
|
11c2e90736 | ||
|
|
816a567f29 | ||
|
|
e35486759b | ||
|
|
b80c81f861 | ||
|
|
005d21c0b6 | ||
|
|
3c8b7a54d6 | ||
|
|
b2d59f2539 | ||
|
|
1cc2830e95 | ||
|
|
9a4d6f6fb7 | ||
|
|
e96db8b69b | ||
|
|
13ce75779f | ||
|
|
cc785ecf4f | ||
|
|
41fe1809da | ||
|
|
fd5d39f4d9 | ||
|
|
71d97ff53a | ||
|
|
f2f3faef08 | ||
|
|
b1a488098b | ||
|
|
fd18a8b82c | ||
|
|
761d2748c5 | ||
|
|
e2f3966763 | ||
|
|
2b3e5461c2 | ||
|
|
ca4db459c4 | ||
|
|
e0d0a5dc31 | ||
|
|
18761a39c4 | ||
|
|
ad25751dbb | ||
|
|
879ca6d149 | ||
|
|
8a40cf421c | ||
|
|
fbbb7b6bf7 | ||
|
|
0596403081 | ||
|
|
d9eb18df4d | ||
|
|
132e4a9839 | ||
|
|
4acf8caac1 | ||
|
|
9de3c88e6b | ||
|
|
6115c9562b | ||
|
|
963a222616 | ||
|
|
7a2de49ac1 | ||
|
|
8380806d7a | ||
|
|
e60479e47a |
26
pom.xml
26
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.5.7.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.4.7.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.8.7.BUILD-SNAPSHOT</springdata.commons>
|
||||
<mongo>2.12.5</mongo>
|
||||
<mongo.osgi>2.12.5</mongo.osgi>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
@@ -108,16 +107,9 @@
|
||||
|
||||
<id>mongo-next</id>
|
||||
<properties>
|
||||
<mongo>2.12.5-SNAPSHOT</mongo>
|
||||
<mongo>2.13.0</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
@@ -148,8 +140,8 @@
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.5.7.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.5.7.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
<artifactId>spring-data-mongodb-distribution</artifactId>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
@@ -13,10 +13,10 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.5.7.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
<properties>
|
||||
<project.root>${basedir}/..</project.root>
|
||||
<dist.key>SDMONGO</dist.key>
|
||||
@@ -32,10 +32,6 @@
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>wagon-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.5.7.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<context version="7.1.10.209">
|
||||
<context version="7.1.9.205">
|
||||
<scope type="Project" name="spring-data-mongodb">
|
||||
<element type="TypeFilterReferenceOverridden" name="Filter">
|
||||
<element type="IncludeTypePattern" name="org.springframework.data.mongodb.**"/>
|
||||
@@ -32,7 +32,6 @@
|
||||
<element type="IncludeTypePattern" name="**.config.**"/>
|
||||
</element>
|
||||
<dependency toName="Project|spring-data-mongodb::Layer|Core::Subsystem|Mapping" type="AllowedDependency"/>
|
||||
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|API" type="AllowedDependency"/>
|
||||
<dependency toName="Project|spring-data-mongodb::Layer|Repositories::Subsystem|Implementation" type="AllowedDependency"/>
|
||||
</element>
|
||||
<dependency toName="Project|spring-data-mongodb::Layer|Config" type="AllowedDependency"/>
|
||||
|
||||
@@ -11,19 +11,18 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.M1</version>
|
||||
<version>1.5.7.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<validation>1.0.0.GA</validation>
|
||||
<objenesis>1.3</objenesis>
|
||||
<equalsverifier>1.5</equalsverifier>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring -->
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
@@ -51,7 +50,7 @@
|
||||
<artifactId>spring-expression</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Data -->
|
||||
<!-- Spring Data -->
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
@@ -145,12 +144,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>nl.jqno.equalsverifier</groupId>
|
||||
<artifactId>equalsverifier</artifactId>
|
||||
<version>${equalsverifier}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -28,9 +28,6 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
@@ -38,8 +35,11 @@ import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.FieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.support.CachingIsNewStrategyFactory;
|
||||
import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -52,10 +52,10 @@ import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
||||
import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
|
||||
|
||||
@@ -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-2013 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.
|
||||
@@ -38,7 +38,6 @@ import com.mongodb.MongoException;
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Komi Innocent
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class DefaultIndexOperations implements IndexOperations {
|
||||
|
||||
@@ -146,13 +145,6 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
|
||||
if (TWO_D_IDENTIFIERS.contains(value)) {
|
||||
indexFields.add(IndexField.geo(key));
|
||||
} else if ("text".equals(value)) {
|
||||
|
||||
DBObject weights = (DBObject) ix.get("weights");
|
||||
for (String fieldName : weights.keySet()) {
|
||||
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Double keyValue = new Double(value.toString());
|
||||
@@ -170,8 +162,8 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
boolean unique = ix.containsField("unique") ? (Boolean) ix.get("unique") : false;
|
||||
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean) ix.get("dropDups") : false;
|
||||
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
|
||||
String language = ix.containsField("default_language") ? (String) ix.get("default_language") : "";
|
||||
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse, language));
|
||||
|
||||
indexInfoList.add(new IndexInfo(indexFields, name, unique, dropDuplicates, sparse));
|
||||
}
|
||||
|
||||
return indexInfoList;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
@@ -19,11 +19,11 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
||||
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
|
||||
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
|
||||
import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
|
||||
@@ -52,6 +52,7 @@ import com.mongodb.WriteResult;
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public interface MongoOperations {
|
||||
|
||||
/**
|
||||
@@ -415,7 +416,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 +427,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}.
|
||||
|
||||
@@ -53,11 +53,9 @@ import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.convert.EntityReader;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResult;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
@@ -73,6 +71,7 @@ import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoWriter;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
||||
import org.springframework.data.mongodb.core.geo.GeoResults;
|
||||
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -336,7 +335,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -567,7 +566,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
BasicDBObject command = new BasicDBObject("geoNear", collection);
|
||||
command.putAll(near.toDBObject());
|
||||
|
||||
CommandResult commandResult = executeCommand(command);
|
||||
CommandResult commandResult = executeCommand(command, getDb().getOptions());
|
||||
List<Object> results = (List<Object>) commandResult.get("results");
|
||||
results = results == null ? Collections.emptyList() : results;
|
||||
|
||||
@@ -746,9 +745,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(entity.getClass());
|
||||
|
||||
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
||||
ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(
|
||||
mongoPersistentEntity.getPropertyAccessor(entity), mongoConverter.getConversionService());
|
||||
accessor.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||
BeanWrapper<Object> wrapper = BeanWrapper.create(entity, this.mongoConverter.getConversionService());
|
||||
wrapper.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,27 +763,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);
|
||||
}
|
||||
}
|
||||
@@ -841,14 +845,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
private <T> void doSaveVersioned(T objectToSave, MongoPersistentEntity<?> entity, String collectionName) {
|
||||
|
||||
ConvertingPropertyAccessor convertingAccessor = new ConvertingPropertyAccessor(
|
||||
entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService());
|
||||
|
||||
BeanWrapper<T> beanWrapper = BeanWrapper.create(objectToSave, this.mongoConverter.getConversionService());
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
MongoPersistentProperty versionProperty = entity.getVersionProperty();
|
||||
|
||||
Object version = convertingAccessor.getProperty(versionProperty);
|
||||
Number versionNumber = convertingAccessor.getProperty(versionProperty, Number.class);
|
||||
Number version = beanWrapper.getProperty(versionProperty, Number.class);
|
||||
|
||||
// Fresh instance -> initialize version property
|
||||
if (version == null) {
|
||||
@@ -858,11 +859,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
// Create query for entity with the id and old version
|
||||
Object id = convertingAccessor.getProperty(idProperty);
|
||||
Object id = beanWrapper.getProperty(idProperty);
|
||||
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
|
||||
|
||||
// Bump version number
|
||||
convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1);
|
||||
Number number = beanWrapper.getProperty(versionProperty, Number.class);
|
||||
beanWrapper.setProperty(versionProperty, number.longValue() + 1);
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
@@ -1012,7 +1014,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("Calling update using query: %s and update: %s in collection: %s",
|
||||
serializeToJsonSafely(queryObj), serializeToJsonSafely(updateObj), collectionName));
|
||||
serializeToJsonSafely(queryObj), serializeToJsonSafely(updateObj), collectionName));
|
||||
}
|
||||
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.UPDATE, collectionName,
|
||||
@@ -1093,11 +1095,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
||||
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
||||
|
||||
if (idProp == null || entity == null) {
|
||||
if (idProp == null) {
|
||||
throw new MappingException("No id property found for object of type " + objectType);
|
||||
}
|
||||
|
||||
Object idValue = entity.getPropertyAccessor(object).getProperty(idProp);
|
||||
Object idValue = BeanWrapper.create(object, mongoConverter.getConversionService())
|
||||
.getProperty(idProp, Object.class);
|
||||
return Collections.singletonMap(idProp.getFieldName(), idValue).entrySet().iterator().next();
|
||||
}
|
||||
|
||||
@@ -1141,11 +1144,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entity.getClass());
|
||||
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
|
||||
|
||||
if (idProperty == null || persistentEntity == null) {
|
||||
if (idProperty == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty);
|
||||
ConversionService service = mongoConverter.getConversionService();
|
||||
Object idValue = BeanWrapper.create(entity, service).getProperty(idProperty, Object.class);
|
||||
|
||||
if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format(
|
||||
@@ -1189,8 +1193,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,
|
||||
@@ -1418,35 +1422,20 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
LOGGER.debug("Executing aggregation: {}", serializeToJsonSafely(command));
|
||||
}
|
||||
|
||||
CommandResult commandResult = executeCommand(command);
|
||||
CommandResult commandResult = executeCommand(command, getDb().getOptions());
|
||||
handleCommandError(commandResult, command);
|
||||
|
||||
return new AggregationResults<O>(returnPotentiallyMappedResults(outputType, commandResult), commandResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the potentially mapped results of the given {@commandResult} contained some.
|
||||
*
|
||||
* @param outputType
|
||||
* @param commandResult
|
||||
* @return
|
||||
*/
|
||||
private <O> List<O> returnPotentiallyMappedResults(Class<O> outputType, CommandResult commandResult) {
|
||||
|
||||
// map results
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterable<DBObject> resultSet = (Iterable<DBObject>) commandResult.get("result");
|
||||
if (resultSet == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<O> mappedResults = new ArrayList<O>();
|
||||
DbObjectCallback<O> callback = new UnwrapAndReadDbObjectCallback<O>(mongoConverter, outputType);
|
||||
|
||||
List<O> mappedResults = new ArrayList<O>();
|
||||
for (DBObject dbObject : resultSet) {
|
||||
mappedResults.add(callback.doWith(dbObject));
|
||||
}
|
||||
|
||||
return mappedResults;
|
||||
return new AggregationResults<O>(mappedResults, commandResult);
|
||||
}
|
||||
|
||||
protected String replaceWithResourceIfNecessary(String function) {
|
||||
@@ -1619,8 +1608,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
CursorPreparer preparer, DbObjectCallback<T> objectCallback) {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
DBObject mappedFields = queryMapper.getMappedFields(fields, entity);
|
||||
DBObject mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
|
||||
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
@@ -1664,7 +1652,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
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));
|
||||
serializeToJsonSafely(query), fields, sort, entityClass, collectionName));
|
||||
}
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort),
|
||||
@@ -1688,9 +1676,9 @@ 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(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));
|
||||
}
|
||||
|
||||
return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
|
||||
@@ -1722,14 +1710,15 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
ConversionService conversionService = mongoConverter.getConversionService();
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(savedObject.getClass());
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject);
|
||||
BeanWrapper<Object> wrapper = BeanWrapper.create(savedObject, conversionService);
|
||||
|
||||
if (accessor.getProperty(idProp) != null) {
|
||||
Object idValue = wrapper.getProperty(idProp, idProp.getType());
|
||||
|
||||
if (idValue != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, id);
|
||||
wrapper.setProperty(idProp, id);
|
||||
}
|
||||
|
||||
private DBCollection getAndPrepareCollection(DB db, String collectionName) {
|
||||
@@ -1973,7 +1962,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
return null;
|
||||
}
|
||||
|
||||
return queryMapper.getMappedSort(query.getSortObject(), mappingContext.getPersistentEntity(type));
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
|
||||
return queryMapper.getMappedObject(query.getSortObject(), entity);
|
||||
}
|
||||
|
||||
// Callback implementations
|
||||
@@ -1998,14 +1988,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(String.format("findOne using query: %s in db.collection: %s", 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()));
|
||||
serializeToJsonSafely(query), fields, collection.getFullName()));
|
||||
}
|
||||
return collection.findOne(query, fields);
|
||||
}
|
||||
@@ -2034,8 +2024,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
public DBCursor doInCollection(DBCollection collection) throws MongoException, DataAccessException {
|
||||
|
||||
if (fields == null || fields.toMap().isEmpty()) {
|
||||
if (fields == null) {
|
||||
return collection.find(query);
|
||||
} else {
|
||||
return collection.find(query, fields);
|
||||
@@ -2190,11 +2179,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
}
|
||||
|
||||
if (query.getSkip() <= 0 && query.getLimit() <= 0 && query.getSortObject() == null
|
||||
&& !StringUtils.hasText(query.getHint()) && !query.getMeta().hasValues()) {
|
||||
&& !StringUtils.hasText(query.getHint())) {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
DBCursor cursorToUse = cursor.copy();
|
||||
DBCursor cursorToUse = cursor;
|
||||
|
||||
try {
|
||||
if (query.getSkip() > 0) {
|
||||
@@ -2210,12 +2199,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
cursorToUse = cursorToUse.hint(query.getHint());
|
||||
}
|
||||
if (query.getMeta().hasValues()) {
|
||||
for (Entry<String, Object> entry : query.getMeta().values()) {
|
||||
cursorToUse = cursorToUse.addSpecial(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -44,23 +44,9 @@ import com.mongodb.DBObject;
|
||||
*/
|
||||
public class Aggregation {
|
||||
|
||||
/**
|
||||
* References the root document, i.e. the top-level document, currently being processed in the aggregation pipeline
|
||||
* stage.
|
||||
*/
|
||||
public static final String ROOT = SystemVariable.ROOT.toString();
|
||||
|
||||
/**
|
||||
* References the start of the field path being processed in the aggregation pipeline stage. Unless documented
|
||||
* otherwise, all stages start with CURRENT the same as ROOT.
|
||||
*/
|
||||
public static final String CURRENT = SystemVariable.CURRENT.toString();
|
||||
|
||||
public static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
|
||||
public static final AggregationOptions DEFAULT_OPTIONS = newAggregationOptions().build();
|
||||
|
||||
protected final List<AggregationOperation> operations;
|
||||
private final AggregationOptions options;
|
||||
private final List<AggregationOperation> operations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||
@@ -80,20 +66,6 @@ public class Aggregation {
|
||||
return new Aggregation(operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@link Aggregation} with the given {@link AggregationOptions} set. Note that options are
|
||||
* supported in MongoDB version 2.6+.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public Aggregation withOptions(AggregationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AggregationOptions must not be null.");
|
||||
return new Aggregation(this.operations, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypedAggregation} for the given type and {@link AggregationOperation}s.
|
||||
*
|
||||
@@ -120,43 +92,11 @@ public class Aggregation {
|
||||
* @param aggregationOperations must not be {@literal null} or empty.
|
||||
*/
|
||||
protected Aggregation(AggregationOperation... aggregationOperations) {
|
||||
this(asAggregationList(aggregationOperations));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aggregationOperations must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
protected static List<AggregationOperation> asAggregationList(AggregationOperation... aggregationOperations) {
|
||||
|
||||
Assert.notEmpty(aggregationOperations, "AggregationOperations must not be null or empty!");
|
||||
|
||||
return Arrays.asList(aggregationOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||
*
|
||||
* @param aggregationOperations must not be {@literal null} or empty.
|
||||
*/
|
||||
protected Aggregation(List<AggregationOperation> aggregationOperations) {
|
||||
this(aggregationOperations, DEFAULT_OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Aggregation} from the given {@link AggregationOperation}s.
|
||||
*
|
||||
* @param aggregationOperations must not be {@literal null} or empty.
|
||||
* @param options must not be {@literal null} or empty.
|
||||
*/
|
||||
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.notNull(options, "AggregationOptions must not be null!");
|
||||
Assert.isTrue(aggregationOperations.length > 0, "At least one AggregationOperation has to be provided");
|
||||
|
||||
this.operations = aggregationOperations;
|
||||
this.options = options;
|
||||
this.operations = Arrays.asList(aggregationOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,16 +231,6 @@ public class Aggregation {
|
||||
return Fields.from(field(name, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link AggregationOptions.Builder}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public static AggregationOptions.Builder newAggregationOptions() {
|
||||
return new AggregationOptions.Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link Aggregation} specification to a {@link DBObject}.
|
||||
*
|
||||
@@ -325,8 +255,6 @@ public class Aggregation {
|
||||
DBObject command = new BasicDBObject("aggregate", inputCollectionName);
|
||||
command.put("pipeline", operationDocuments);
|
||||
|
||||
command = options.applyAndReturnPotentiallyChangedCommand(command);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -374,51 +302,4 @@ public class Aggregation {
|
||||
return new FieldReference(new ExposedField(new AggregationField(name), true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the system variables available in MongoDB aggregation framework pipeline expressions.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation-variables
|
||||
*/
|
||||
enum SystemVariable {
|
||||
|
||||
ROOT, CURRENT;
|
||||
|
||||
private static final String PREFIX = "$$";
|
||||
|
||||
/**
|
||||
* Return {@literal true} if the given {@code fieldRef} denotes a well-known system variable, {@literal false}
|
||||
* otherwise.
|
||||
*
|
||||
* @param fieldRef may be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static boolean isReferingToSystemVariable(String fieldRef) {
|
||||
|
||||
if (fieldRef == null || !fieldRef.startsWith(PREFIX) || fieldRef.length() <= 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int indexOfFirstDot = fieldRef.indexOf('.');
|
||||
String candidate = fieldRef.substring(2, indexOfFirstDot == -1 ? fieldRef.length() : indexOfFirstDot);
|
||||
|
||||
for (SystemVariable value : values()) {
|
||||
if (value.name().equals(candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Enum#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return PREFIX.concat(name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Holds a set of configurable aggregation options that can be used within an aggregation pipeline. A list of support
|
||||
* aggregation options can be found in the MongoDB reference documentation
|
||||
* http://docs.mongodb.org/manual/reference/command/aggregate/#aggregate
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @see Aggregation#withOptions(AggregationOptions)
|
||||
* @see TypedAggregation#withOptions(AggregationOptions)
|
||||
* @since 1.6
|
||||
*/
|
||||
public class AggregationOptions {
|
||||
|
||||
private static final String CURSOR = "cursor";
|
||||
private static final String EXPLAIN = "explain";
|
||||
private static final String ALLOW_DISK_USE = "allowDiskUse";
|
||||
|
||||
private final boolean allowDiskUse;
|
||||
private final boolean explain;
|
||||
private final DBObject cursor;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AggregationOptions}.
|
||||
*
|
||||
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
|
||||
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
|
||||
* @param cursor can be {@literal null}, used to pass additional options to the aggregation.
|
||||
*/
|
||||
public AggregationOptions(boolean allowDiskUse, boolean explain, DBObject cursor) {
|
||||
|
||||
this.allowDiskUse = allowDiskUse;
|
||||
this.explain = explain;
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables writing to temporary files. When set to true, aggregation stages can write data to the _tmp subdirectory in
|
||||
* the dbPath directory.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAllowDiskUse() {
|
||||
return allowDiskUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies to return the information on the processing of the pipeline.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplain() {
|
||||
return explain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a document that contains options that control the creation of the cursor object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DBObject getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potentially adjusted copy for the given {@code aggregationCommandObject} with the configuration
|
||||
* applied.
|
||||
*
|
||||
* @param command the aggregation command.
|
||||
* @return
|
||||
*/
|
||||
DBObject applyAndReturnPotentiallyChangedCommand(DBObject command) {
|
||||
|
||||
DBObject result = new BasicDBObject(command.toMap());
|
||||
|
||||
if (allowDiskUse && !result.containsField(ALLOW_DISK_USE)) {
|
||||
result.put(ALLOW_DISK_USE, allowDiskUse);
|
||||
}
|
||||
|
||||
if (explain && !result.containsField(EXPLAIN)) {
|
||||
result.put(EXPLAIN, explain);
|
||||
}
|
||||
|
||||
if (cursor != null && !result.containsField(CURSOR)) {
|
||||
result.put("cursor", cursor);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link DBObject} representation of this {@link AggregationOptions}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DBObject toDbObject() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
dbo.put(ALLOW_DISK_USE, allowDiskUse);
|
||||
dbo.put(EXPLAIN, explain);
|
||||
dbo.put(CURSOR, cursor);
|
||||
|
||||
return dbo;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toDbObject().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A Builder for {@link AggregationOptions}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private boolean allowDiskUse;
|
||||
private boolean explain;
|
||||
private DBObject cursor;
|
||||
|
||||
/**
|
||||
* Defines whether to off-load intensive sort-operations to disk.
|
||||
*
|
||||
* @param allowDiskUse
|
||||
* @return
|
||||
*/
|
||||
public Builder allowDiskUse(boolean allowDiskUse) {
|
||||
|
||||
this.allowDiskUse = allowDiskUse;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines whether to get the execution plan for the aggregation instead of the actual results.
|
||||
*
|
||||
* @param explain
|
||||
* @return
|
||||
*/
|
||||
public Builder explain(boolean explain) {
|
||||
|
||||
this.explain = explain;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional options to the aggregation.
|
||||
*
|
||||
* @param cursor
|
||||
* @return
|
||||
*/
|
||||
public Builder cursor(DBObject cursor) {
|
||||
|
||||
this.cursor = cursor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link AggregationOptions} instance with the given configuration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AggregationOptions build() {
|
||||
return new AggregationOptions(allowDiskUse, explain, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013 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,7 +28,6 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @param <T> The class in which the results are mapped onto.
|
||||
* @since 1.3
|
||||
*/
|
||||
@@ -91,16 +90,6 @@ public class AggregationResults<T> implements Iterable<T> {
|
||||
return serverUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw result that was returned by the server.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public DBObject getRawResults() {
|
||||
return rawResults;
|
||||
}
|
||||
|
||||
private String parseServerUsed() {
|
||||
|
||||
Object object = rawResults.get("serverUsed");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.springframework.util.StringUtils;
|
||||
* Value object to capture a list of {@link Field} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @since 1.3
|
||||
*/
|
||||
public final class Fields implements Iterable<Field> {
|
||||
@@ -187,7 +186,7 @@ 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
|
||||
* Creates an aggregation fieldwith the given name. As no target is set explicitly, the name will be used as target
|
||||
* as well.
|
||||
*
|
||||
* @param key
|
||||
@@ -218,10 +217,6 @@ public final class Fields implements Iterable<Field> {
|
||||
return source;
|
||||
}
|
||||
|
||||
if (Aggregation.SystemVariable.isReferingToSystemVariable(source)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
int dollarIndex = source.lastIndexOf('$');
|
||||
return dollarIndex == -1 ? source : source.substring(dollarIndex + 1);
|
||||
}
|
||||
|
||||
@@ -364,16 +364,7 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
}
|
||||
|
||||
public Object getValue(AggregationOperationContext context) {
|
||||
|
||||
if (reference == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Aggregation.SystemVariable.isReferingToSystemVariable(reference)) {
|
||||
return reference;
|
||||
}
|
||||
|
||||
return context.getReference(reference).toString();
|
||||
return reference == null ? value : context.getReference(reference).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -34,6 +35,18 @@ public class MatchOperation implements AggregationOperation {
|
||||
|
||||
private final CriteriaDefinition criteriaDefinition;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MatchOperation} for the given {@link Criteria}.
|
||||
*
|
||||
* @param criteria must not be {@literal null}.
|
||||
* @deprecated Use {@link MatchOperation#MatchOperation(CriteriaDefinition)} instead. This constructor is scheduled
|
||||
* for removal in the next versions.
|
||||
*/
|
||||
@Deprecated
|
||||
public MatchOperation(Criteria criteria) {
|
||||
this((CriteriaDefinition) criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MatchOperation} for the given {@link CriteriaDefinition}.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedFi
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
@@ -234,53 +235,26 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link ProjectionOperationBuilder} that is used for SpEL expression based projections.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public static class ExpressionProjectionOperationBuilder extends ProjectionOperationBuilder {
|
||||
public static class ExpressionProjectionOperationBuilder extends AbstractProjectionOperationBuilder {
|
||||
|
||||
private final Object[] params;
|
||||
private final String expression;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionProjectionOperationBuilder} for the given value, {@link ProjectionOperation} and
|
||||
* parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
* @param parameters
|
||||
*/
|
||||
public ExpressionProjectionOperationBuilder(String expression, ProjectionOperation operation, Object[] parameters) {
|
||||
public ExpressionProjectionOperationBuilder(Object value, ProjectionOperation operation, Object[] parameters) {
|
||||
|
||||
super(expression, operation, null);
|
||||
this.expression = expression;
|
||||
super(value, operation);
|
||||
this.params = parameters.clone();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder#project(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public ProjectionOperationBuilder project(String operation, final Object... values) {
|
||||
|
||||
OperationProjection operationProjection = new OperationProjection(Fields.field(value.toString()), operation,
|
||||
values) {
|
||||
@Override
|
||||
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||
|
||||
List<Object> result = new ArrayList<Object>(values.length + 1);
|
||||
result.add(ExpressionProjection.toMongoExpression(context,
|
||||
ExpressionProjectionOperationBuilder.this.expression, ExpressionProjectionOperationBuilder.this.params));
|
||||
result.addAll(Arrays.asList(values));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return new ProjectionOperationBuilder(value, this.operation.and(operationProjection), operationProjection);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.AbstractProjectionOperationBuilder#as(java.lang.String)
|
||||
@@ -329,11 +303,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
*/
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
return new BasicDBObject(getExposedField().getName(), toMongoExpression(context, expression, params));
|
||||
}
|
||||
|
||||
protected static Object toMongoExpression(AggregationOperationContext context, String expression, Object[] params) {
|
||||
return TRANSFORMER.transform(expression, context, params);
|
||||
return new BasicDBObject(getExposedField().getName(), TRANSFORMER.transform(expression, context, params));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,6 +320,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
private static final String FIELD_REFERENCE_NOT_NULL = "Field reference must not be null!";
|
||||
|
||||
private final String name;
|
||||
private final ProjectionOperation operation;
|
||||
private final OperationProjection previousProjection;
|
||||
|
||||
/**
|
||||
@@ -364,23 +335,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
super(name, operation);
|
||||
|
||||
this.name = name;
|
||||
this.previousProjection = previousProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ProjectionOperationBuilder} for the field with the given value on top of the given
|
||||
* {@link ProjectionOperation}.
|
||||
*
|
||||
* @param value
|
||||
* @param operation
|
||||
* @param previousProjection
|
||||
*/
|
||||
protected ProjectionOperationBuilder(Object value, ProjectionOperation operation,
|
||||
OperationProjection previousProjection) {
|
||||
|
||||
super(value, operation);
|
||||
|
||||
this.name = null;
|
||||
this.operation = operation;
|
||||
this.previousProjection = previousProjection;
|
||||
}
|
||||
|
||||
@@ -566,9 +521,8 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder project(String operation, Object... values) {
|
||||
OperationProjection operationProjection = new OperationProjection(Fields.field(value.toString()), operation,
|
||||
values);
|
||||
return new ProjectionOperationBuilder(value, this.operation.and(operationProjection), operationProjection);
|
||||
OperationProjection projectionOperation = new OperationProjection(Fields.field(name), operation, values);
|
||||
return new ProjectionOperationBuilder(name, this.operation.and(projectionOperation), projectionOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -673,10 +627,6 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
// implicit reference or explicit include?
|
||||
if (value == null || Boolean.TRUE.equals(value)) {
|
||||
|
||||
if (Aggregation.SystemVariable.isReferingToSystemVariable(field.getTarget())) {
|
||||
return field.getTarget();
|
||||
}
|
||||
|
||||
// check whether referenced field exists in the context
|
||||
return context.getReference(field).getReferenceValue();
|
||||
|
||||
@@ -699,7 +649,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
/**
|
||||
* Creates a new {@link OperationProjection} for the given field.
|
||||
*
|
||||
* @param field the name of the field to add the operation projection for, must not be {@literal null} or empty.
|
||||
* @param name the name of the field to add the operation projection for, must not be {@literal null} or empty.
|
||||
* @param operation the actual operation key, must not be {@literal null} or empty.
|
||||
* @param values the values to pass into the operation, must not be {@literal null}.
|
||||
*/
|
||||
@@ -722,15 +672,18 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
|
||||
DBObject inner = new BasicDBObject("$" + operation, getOperationArguments(context));
|
||||
BasicDBList values = new BasicDBList();
|
||||
values.addAll(buildReferences(context));
|
||||
|
||||
return new BasicDBObject(getField().getName(), inner);
|
||||
DBObject inner = new BasicDBObject("$" + operation, values);
|
||||
|
||||
return new BasicDBObject(this.field.getName(), inner);
|
||||
}
|
||||
|
||||
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||
private List<Object> buildReferences(AggregationOperationContext context) {
|
||||
|
||||
List<Object> result = new ArrayList<Object>(values.size());
|
||||
result.add(context.getReference(getField().getName()).toString());
|
||||
result.add(context.getReference(field.getTarget()).toString());
|
||||
|
||||
for (Object element : values) {
|
||||
result.add(element instanceof Field ? context.getReference((Field) element).toString() : element);
|
||||
@@ -739,15 +692,6 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field that holds the {@link OperationProjection}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Field getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link OperationProjection} with the given alias.
|
||||
*
|
||||
@@ -755,27 +699,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
* @return
|
||||
*/
|
||||
public OperationProjection withAlias(String alias) {
|
||||
|
||||
final Field aliasedField = Fields.field(alias, this.field.getName());
|
||||
return new OperationProjection(aliasedField, operation, values.toArray()) {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.OperationProjection#getField()
|
||||
*/
|
||||
@Override
|
||||
protected Field getField() {
|
||||
return aliasedField;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||
|
||||
// We have to make sure that we use the arguments from the "previous" OperationProjection that we replace
|
||||
// with this new instance.
|
||||
|
||||
return OperationProjection.this.getOperationArguments(context);
|
||||
}
|
||||
};
|
||||
return new OperationProjection(Fields.field(alias, this.field.getName()), operation, values.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,96 +731,6 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return new BasicDBObject(name, nestedObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the minute from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractMinute() {
|
||||
return project("minute");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the hour from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractHour() {
|
||||
return project("hour");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the second from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractSecond() {
|
||||
return project("second");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the millisecond from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractMillisecond() {
|
||||
return project("millisecond");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the year from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractYear() {
|
||||
return project("year");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the month from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractMonth() {
|
||||
return project("month");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the week from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractWeek() {
|
||||
return project("week");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the dayOfYear from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractDayOfYear() {
|
||||
return project("dayOfYear");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the dayOfMonth from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractDayOfMonth() {
|
||||
return project("dayOfMonth");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the dayOfWeek from a date expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ProjectionOperationBuilder extractDayOfWeek() {
|
||||
return project("dayOfWeek");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -937,4 +771,5 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
*/
|
||||
public abstract DBObject toDBObject(AggregationOperationContext context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013 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.aggregation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -32,34 +30,11 @@ public class TypedAggregation<I> extends Aggregation {
|
||||
/**
|
||||
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s.
|
||||
*
|
||||
* @param inputType must not be {@literal null}.
|
||||
* @param operations must not be {@literal null} or empty.
|
||||
*/
|
||||
public TypedAggregation(Class<I> inputType, AggregationOperation... operations) {
|
||||
this(inputType, asAggregationList(operations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s.
|
||||
*
|
||||
* @param inputType must not be {@literal null}.
|
||||
* @param operations must not be {@literal null} or empty.
|
||||
*/
|
||||
public TypedAggregation(Class<I> inputType, List<AggregationOperation> operations) {
|
||||
this(inputType, operations, DEFAULT_OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypedAggregation} from the given {@link AggregationOperation}s and the given
|
||||
* {@link AggregationOptions}.
|
||||
*
|
||||
* @param inputType must not be {@literal null}.
|
||||
* @param operations must not be {@literal null} or empty.
|
||||
* @param options must not be {@literal null}.
|
||||
*/
|
||||
public TypedAggregation(Class<I> inputType, List<AggregationOperation> operations, AggregationOptions options) {
|
||||
|
||||
super(operations, options);
|
||||
super(operations);
|
||||
|
||||
Assert.notNull(inputType, "Input type must not be null!");
|
||||
this.inputType = inputType;
|
||||
@@ -73,14 +48,4 @@ public class TypedAggregation<I> extends Aggregation {
|
||||
public Class<I> getInputType() {
|
||||
return inputType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.Aggregation#withOptions(org.springframework.data.mongodb.core.aggregation.AggregationOptions)
|
||||
*/
|
||||
public TypedAggregation<I> withOptions(AggregationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AggregationOptions must not be null.");
|
||||
return new TypedAggregation<I>(inputType, operations, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
@@ -36,7 +37,6 @@ import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
|
||||
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.WritingConverter;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
@@ -46,7 +46,6 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.DBObjectToS
|
||||
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.util.Assert;
|
||||
@@ -60,7 +59,6 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class CustomConversions {
|
||||
|
||||
@@ -72,10 +70,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> customReadTargetTypes;
|
||||
private final Map<ConvertiblePair, CacheValue> customWriteTargetTypes;
|
||||
private final Map<Class<?>, CacheValue> rawWriteTargetTypes;
|
||||
|
||||
/**
|
||||
* Creates an empty {@link CustomConversions} object.
|
||||
*/
|
||||
@@ -95,7 +96,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>();
|
||||
this.customWriteTargetTypes = new ConcurrentHashMap<ConvertiblePair, CacheValue>();
|
||||
this.rawWriteTargetTypes = new ConcurrentHashMap<Class<?>, CacheValue>();
|
||||
|
||||
List<Object> toRegister = new ArrayList<Object>();
|
||||
|
||||
@@ -109,11 +112,9 @@ public class CustomConversions {
|
||||
toRegister.add(URLToStringConverter.INSTANCE);
|
||||
toRegister.add(StringToURLConverter.INSTANCE);
|
||||
toRegister.add(DBObjectToStringConverter.INSTANCE);
|
||||
toRegister.add(TermToStringConverter.INSTANCE);
|
||||
|
||||
|
||||
toRegister.addAll(JodaTimeConverters.getConvertersToRegister());
|
||||
toRegister.addAll(GeoConverters.getConvertersToRegister());
|
||||
toRegister.addAll(Jsr310Converters.getConvertersToRegister());
|
||||
|
||||
for (Object c : toRegister) {
|
||||
registerConversion(c);
|
||||
@@ -240,70 +241,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 +346,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 +368,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> cache, Producer producer) {
|
||||
|
||||
Assert.notNull(sourceType);
|
||||
CacheValue cacheValue = cache.get(key);
|
||||
|
||||
if (requestedTargetType == null) {
|
||||
return null;
|
||||
if (cacheValue != null) {
|
||||
return cacheValue.getType();
|
||||
}
|
||||
|
||||
ConvertiblePair lookupKey = new ConvertiblePair(sourceType, requestedTargetType);
|
||||
CacheValue readTargetTypeValue = customReadTargetTypes.get(lookupKey);
|
||||
Class<?> type = producer.get();
|
||||
cache.put(key, CacheValue.of(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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -87,12 +92,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()) {
|
||||
@@ -108,14 +117,14 @@ class DBObjectAccessor {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Object, Object> getAsMap(Object source) {
|
||||
private 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;
|
||||
|
||||
@@ -39,8 +39,7 @@ public interface DbRefResolver {
|
||||
* @param callback will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler proxyHandler);
|
||||
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback);
|
||||
|
||||
/**
|
||||
* Creates a {@link DBRef} instance for the given {@link org.springframework.data.mongodb.core.mapping.DBRef}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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 org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultDbRefProxyHandler implements DbRefProxyHandler {
|
||||
|
||||
private final SpELContext spELContext;
|
||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||
private final ValueResolver resolver;
|
||||
|
||||
/**
|
||||
* @param spELContext must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public DefaultDbRefProxyHandler(SpELContext spELContext,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext, ValueResolver resolver) {
|
||||
|
||||
this.spELContext = spELContext;
|
||||
this.mappingContext = mappingContext;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefProxyHandler#populateId(com.mongodb.DBRef, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object populateId(MongoPersistentProperty property, DBRef source, Object proxy) {
|
||||
|
||||
if (source == null) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(property);
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (idProperty.usePropertyAccess()) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext);
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(proxy);
|
||||
|
||||
DBObject object = new BasicDBObject(idProperty.getFieldName(), source.getId());
|
||||
ObjectPath objectPath = ObjectPath.ROOT.push(proxy, entity, null);
|
||||
accessor.setProperty(idProperty, resolver.getValueInternal(idProperty, object, evaluator, objectPath));
|
||||
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,10 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.objenesis.Objenesis;
|
||||
import org.objenesis.ObjenesisStd;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
@@ -36,8 +39,8 @@ import org.springframework.data.mongodb.LazyLoadingException;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.objenesis.ObjenesisStd;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -54,9 +57,10 @@ import com.mongodb.DBRef;
|
||||
*/
|
||||
public class DefaultDbRefResolver implements DbRefResolver {
|
||||
|
||||
private static final boolean OBJENESIS_PRESENT = ClassUtils.isPresent("org.objenesis.Objenesis", null);
|
||||
|
||||
private final MongoDbFactory mongoDbFactory;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private final ObjenesisStd objenesis;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}.
|
||||
@@ -69,7 +73,6 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||
this.objenesis = new ObjenesisStd(true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,14 +80,13 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
|
||||
*/
|
||||
@Override
|
||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler handler) {
|
||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
Assert.notNull(callback, "Callback must not be null!");
|
||||
|
||||
if (isLazyDbRef(property)) {
|
||||
return createLazyLoadingProxy(property, dbref, callback, handler);
|
||||
return createLazyLoadingProxy(property, dbref, callback);
|
||||
}
|
||||
|
||||
return callback.resolve(property);
|
||||
@@ -113,47 +115,34 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
* @param callback must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler handler) {
|
||||
|
||||
Class<?> propertyType = property.getType();
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||
|
||||
if (!propertyType.isInterface()) {
|
||||
|
||||
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType));
|
||||
factory.setCallbacks(new Callback[] { interceptor });
|
||||
|
||||
return handler.populateId(property, dbref, factory);
|
||||
}
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
Class<?> propertyType = property.getType();
|
||||
|
||||
for (Class<?> type : propertyType.getInterfaces()) {
|
||||
proxyFactory.addInterface(type);
|
||||
}
|
||||
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||
|
||||
proxyFactory.addInterface(LazyLoadingProxy.class);
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
|
||||
return handler.populateId(property, dbref, proxyFactory.getProxy());
|
||||
}
|
||||
if (propertyType.isInterface()) {
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
return proxyFactory.getProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CGLib enhanced type for the given source type.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getEnhancedTypeFor(Class<?> type) {
|
||||
proxyFactory.setProxyTargetClass(true);
|
||||
proxyFactory.setTargetClass(propertyType);
|
||||
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(type);
|
||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class });
|
||||
if (!OBJENESIS_PRESENT) {
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
return proxyFactory.getProxy();
|
||||
}
|
||||
|
||||
return enhancer.createClass();
|
||||
return ObjenesisProxyEnhancer.enhanceAndGet(proxyFactory, propertyType, interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,12 +162,11 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
||||
Serializable {
|
||||
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD;
|
||||
|
||||
private final DbRefResolverCallback callback;
|
||||
private final MongoPersistentProperty property;
|
||||
@@ -190,9 +178,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
|
||||
static {
|
||||
try {
|
||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("getTarget");
|
||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("initialize");
|
||||
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||
FINALIZE_METHOD = Object.class.getDeclaredMethod("finalize");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -256,11 +243,6 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||
return proxyHashCode(proxy);
|
||||
}
|
||||
|
||||
// DATAMONGO-1076 - finalize methods should not trigger proxy initialization
|
||||
if (FINALIZE_METHOD.equals(method)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Object target = ensureResolved();
|
||||
@@ -389,4 +371,109 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static class to accommodate optional dependency on Objenesis.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @since 1.4
|
||||
*/
|
||||
private static class ObjenesisProxyEnhancer {
|
||||
|
||||
private static final boolean IS_SPRING_4_OR_BETTER = ClassUtils.isPresent(
|
||||
"org.springframework.core.DefaultParameterNameDiscoverer", null);
|
||||
|
||||
private static final InstanceCreatorStrategy INSTANCE_CREATOR;
|
||||
|
||||
static {
|
||||
|
||||
if (IS_SPRING_4_OR_BETTER) {
|
||||
INSTANCE_CREATOR = new Spring4ObjenesisInstanceCreatorStrategy();
|
||||
} else {
|
||||
INSTANCE_CREATOR = new DefaultObjenesisInstanceCreatorStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object enhanceAndGet(ProxyFactory proxyFactory, Class<?> type,
|
||||
org.springframework.cglib.proxy.MethodInterceptor interceptor) {
|
||||
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(type);
|
||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class });
|
||||
|
||||
Factory factory = (Factory) INSTANCE_CREATOR.newInstance(enhancer.createClass());
|
||||
factory.setCallbacks(new Callback[] { interceptor });
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy for constructing new instances of a given {@link Class}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
interface InstanceCreatorStrategy {
|
||||
Object newInstance(Class<?> clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link InstanceCreatorStrategy} that uses Objenesis from the classpath.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
private static class DefaultObjenesisInstanceCreatorStrategy implements InstanceCreatorStrategy {
|
||||
|
||||
private static final Objenesis OBJENESIS = new ObjenesisStd(true);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.ObjenesisProxyEnhancer.InstanceCreatorStrategy#newInstance(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Object newInstance(Class<?> clazz) {
|
||||
return OBJENESIS.newInstance(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link InstanceCreatorStrategy} that uses a repackaged version of Objenesis from Spring 4.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
private static class Spring4ObjenesisInstanceCreatorStrategy implements InstanceCreatorStrategy {
|
||||
|
||||
private static final String SPRING4_OBJENESIS_CLASS_NAME = "org.springframework.objenesis.ObjenesisStd";
|
||||
private static final Object OBJENESIS;
|
||||
private static final Method NEW_INSTANCE_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
try {
|
||||
Class<?> objenesisClass = ClassUtils.forName(SPRING4_OBJENESIS_CLASS_NAME,
|
||||
ObjenesisProxyEnhancer.class.getClassLoader());
|
||||
|
||||
OBJENESIS = BeanUtils.instantiateClass(objenesisClass.getConstructor(boolean.class), true);
|
||||
NEW_INSTANCE_METHOD = objenesisClass.getMethod("newInstance", Class.class);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not setup Objenesis infrastructure with Spring 4 ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.ObjenesisProxyEnhancer.InstanceCreatorStrategy#newInstance(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Object newInstance(Class<?> clazz) {
|
||||
|
||||
try {
|
||||
return NEW_INSTANCE_METHOD.invoke(OBJENESIS, clazz);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not created instance for " + clazz, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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 org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link DbRefResolverCallback}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultDbRefResolverCallback implements DbRefResolverCallback {
|
||||
|
||||
private final DBObject surroundingObject;
|
||||
private final ObjectPath path;
|
||||
private final ValueResolver resolver;
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link DBObject}, {@link ObjectPath},
|
||||
* {@link ValueResolver} and {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param surroundingObject must not be {@literal null}.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param resolver must not be {@literal null}.
|
||||
*/
|
||||
public DefaultDbRefResolverCallback(DBObject surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
|
||||
ValueResolver resolver) {
|
||||
|
||||
this.surroundingObject = surroundingObject;
|
||||
this.path = path;
|
||||
this.resolver = resolver;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolverCallback#resolve(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public Object resolve(MongoPersistentProperty property) {
|
||||
return resolver.getValueInternal(property, surroundingObject, evaluator, path);
|
||||
}
|
||||
}
|
||||
@@ -57,15 +57,18 @@ abstract class GeoConverters {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Collection<? extends Object> getConvertersToRegister() {
|
||||
return Arrays.asList( //
|
||||
BoxToDbObjectConverter.INSTANCE //
|
||||
, PolygonToDbObjectConverter.INSTANCE //
|
||||
, CircleToDbObjectConverter.INSTANCE //
|
||||
, LegacyCircleToDbObjectConverter.INSTANCE //
|
||||
, SphereToDbObjectConverter.INSTANCE //
|
||||
, DbObjectToBoxConverter.INSTANCE //
|
||||
, DbObjectToPolygonConverter.INSTANCE //
|
||||
, DbObjectToCircleConverter.INSTANCE //
|
||||
, DbObjectToLegacyCircleConverter.INSTANCE //
|
||||
, DbObjectToSphereConverter.INSTANCE //
|
||||
, DbObjectToPointConverter.INSTANCE //
|
||||
, PointToDbObjectConverter.INSTANCE //
|
||||
@@ -88,11 +91,13 @@ abstract class GeoConverters {
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Point convert(DBObject source) {
|
||||
|
||||
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 source == null ? null : new org.springframework.data.mongodb.core.geo.Point((Double) source.get("x"),
|
||||
(Double) source.get("y"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +151,7 @@ abstract class GeoConverters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link BasicDBList} into a {@link Box}.
|
||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Box}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
@@ -161,6 +166,7 @@ abstract class GeoConverters {
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Box convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
@@ -170,7 +176,7 @@ abstract class GeoConverters {
|
||||
Point first = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("first"));
|
||||
Point second = DbObjectToPointConverter.INSTANCE.convert((DBObject) source.get("second"));
|
||||
|
||||
return new Box(first, second);
|
||||
return new org.springframework.data.mongodb.core.geo.Box(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +210,7 @@ abstract class GeoConverters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link DBObject} into a {@link Circle}.
|
||||
* Converts a {@link DBObject} into a {@link org.springframework.data.mongodb.core.geo.Circle}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
@@ -245,6 +251,71 @@ abstract class GeoConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Circle} into a {@link BasicDBList}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static enum LegacyCircleToDbObjectConverter implements
|
||||
Converter<org.springframework.data.mongodb.core.geo.Circle, DBObject> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public DBObject convert(org.springframework.data.mongodb.core.geo.Circle source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DBObject result = new BasicDBObject();
|
||||
result.put("center", PointToDbObjectConverter.INSTANCE.convert(source.getCenter()));
|
||||
result.put("radius", source.getRadius());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Circle}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
@ReadingConverter
|
||||
@SuppressWarnings("deprecation")
|
||||
public static enum DbObjectToLegacyCircleConverter implements
|
||||
Converter<DBObject, org.springframework.data.mongodb.core.geo.Circle> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public org.springframework.data.mongodb.core.geo.Circle convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DBObject centerSource = (DBObject) source.get("center");
|
||||
Double radius = (Double) source.get("radius");
|
||||
|
||||
Assert.notNull(centerSource, "Center must not be null!");
|
||||
Assert.notNull(radius, "Radius must not be null!");
|
||||
|
||||
Point center = DbObjectToPointConverter.INSTANCE.convert(centerSource);
|
||||
return new org.springframework.data.mongodb.core.geo.Circle(center, radius);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Sphere} into a {@link BasicDBList}.
|
||||
*
|
||||
@@ -351,7 +422,7 @@ abstract class GeoConverters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link BasicDBList} into a {@link Polygon}.
|
||||
* Converts a {@link BasicDBList} into a {@link org.springframework.data.mongodb.core.geo.Polygon}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
@@ -366,7 +437,7 @@ abstract class GeoConverters {
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||
public Polygon convert(DBObject source) {
|
||||
|
||||
if (source == null) {
|
||||
@@ -382,7 +453,7 @@ abstract class GeoConverters {
|
||||
newPoints.add(DbObjectToPointConverter.INSTANCE.convert(element));
|
||||
}
|
||||
|
||||
return new Polygon(newPoints);
|
||||
return new org.springframework.data.mongodb.core.geo.Polygon(newPoints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +472,7 @@ abstract class GeoConverters {
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public DBObject convert(GeoCommand source) {
|
||||
|
||||
if (source == null) {
|
||||
@@ -421,10 +493,10 @@ abstract class GeoConverters {
|
||||
argument.add(toList(((Circle) shape).getCenter()));
|
||||
argument.add(((Circle) shape).getRadius().getNormalizedValue());
|
||||
|
||||
} else if (shape instanceof Circle) {
|
||||
} else if (shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
|
||||
|
||||
argument.add(toList(((Circle) shape).getCenter()));
|
||||
argument.add(((Circle) shape).getRadius());
|
||||
argument.add(toList(((org.springframework.data.mongodb.core.geo.Circle) shape).getCenter()));
|
||||
argument.add(((org.springframework.data.mongodb.core.geo.Circle) shape).getRadius());
|
||||
|
||||
} else if (shape instanceof Polygon) {
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.mongodb.DBRef;
|
||||
* Allows direct interaction with the underlying {@link LazyLoadingInterceptor}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface LazyLoadingProxy {
|
||||
@@ -34,7 +33,7 @@ public interface LazyLoadingProxy {
|
||||
* @return
|
||||
* @since 1.5
|
||||
*/
|
||||
Object getTarget();
|
||||
Object initialize();
|
||||
|
||||
/**
|
||||
* Returns the {@link DBRef} represented by this {@link LazyLoadingProxy}, may be null.
|
||||
|
||||
@@ -31,17 +31,16 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.data.convert.CollectionFactory;
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.AssociationHandler;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
@@ -75,7 +74,7 @@ import com.mongodb.DBRef;
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware, ValueResolver {
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||
|
||||
private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s! Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions. Parent object was: %4$s";
|
||||
|
||||
@@ -85,7 +84,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||
protected final QueryMapper idMapper;
|
||||
protected final DbRefResolver dbRefResolver;
|
||||
|
||||
protected ApplicationContext applicationContext;
|
||||
protected MongoTypeMapper typeMapper;
|
||||
protected String mapKeyDotReplacement = null;
|
||||
@@ -98,10 +96,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
super(new DefaultConversionService());
|
||||
super(ConversionServiceFactory.createDefaultConversionService());
|
||||
|
||||
Assert.notNull(dbRefResolver, "DbRefResolver must not be null!");
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
@@ -188,11 +187,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
protected <S extends Object> S read(TypeInformation<S> type, DBObject dbo) {
|
||||
return read(type, dbo, ObjectPath.ROOT);
|
||||
return read(type, dbo, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends Object> S read(TypeInformation<S> type, DBObject dbo, ObjectPath path) {
|
||||
protected <S extends Object> S read(TypeInformation<S> type, DBObject dbo, Object parent) {
|
||||
|
||||
if (null == dbo) {
|
||||
return null;
|
||||
@@ -210,15 +209,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
if (typeToUse.isCollectionLike() && dbo instanceof BasicDBList) {
|
||||
return (S) readCollectionOrArray(typeToUse, (BasicDBList) dbo, path);
|
||||
return (S) readCollectionOrArray(typeToUse, (BasicDBList) dbo, parent);
|
||||
}
|
||||
|
||||
if (typeToUse.isMap()) {
|
||||
return (S) readMap(typeToUse, dbo, path);
|
||||
return (S) readMap(typeToUse, dbo, parent);
|
||||
}
|
||||
|
||||
if (dbo instanceof BasicDBList) {
|
||||
throw new MappingException(String.format(INCOMPATIBLE_TYPES, dbo, BasicDBList.class, typeToUse.getType(), path));
|
||||
throw new MappingException(String.format(INCOMPATIBLE_TYPES, dbo, BasicDBList.class, typeToUse.getType(), parent));
|
||||
}
|
||||
|
||||
// Retrieve persistent entity info
|
||||
@@ -228,57 +227,40 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
throw new MappingException("No mapping metadata found for " + rawType.getName());
|
||||
}
|
||||
|
||||
return read(persistentEntity, dbo, path);
|
||||
return read(persistentEntity, dbo, parent);
|
||||
}
|
||||
|
||||
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(MongoPersistentEntity<?> entity,
|
||||
DBObject source, DefaultSpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||
DBObject source, DefaultSpELExpressionEvaluator evaluator, Object parent) {
|
||||
|
||||
MongoDbPropertyValueProvider provider = new MongoDbPropertyValueProvider(source, evaluator, path);
|
||||
MongoDbPropertyValueProvider provider = new MongoDbPropertyValueProvider(source, evaluator, parent);
|
||||
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<MongoPersistentProperty>(
|
||||
entity, provider, path.getCurrentObject());
|
||||
entity, provider, parent);
|
||||
|
||||
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider, path);
|
||||
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider,
|
||||
parent);
|
||||
}
|
||||
|
||||
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final ObjectPath path) {
|
||||
private <S extends Object> S read(final MongoPersistentEntity<S> entity, final DBObject dbo, final Object parent) {
|
||||
|
||||
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(dbo, spELContext);
|
||||
|
||||
ParameterValueProvider<MongoPersistentProperty> provider = getParameterProvider(entity, dbo, evaluator, path);
|
||||
ParameterValueProvider<MongoPersistentProperty> provider = getParameterProvider(entity, dbo, evaluator, parent);
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
S instance = instantiator.createInstance(entity, provider);
|
||||
|
||||
final PersistentPropertyAccessor accessor = new ConvertingPropertyAccessor(entity.getPropertyAccessor(instance),
|
||||
conversionService);
|
||||
|
||||
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
final S result = instance;
|
||||
|
||||
// make sure id property is set before all other properties
|
||||
Object idValue = null;
|
||||
|
||||
if (idProperty != null) {
|
||||
idValue = getValueInternal(idProperty, dbo, evaluator, path);
|
||||
accessor.setProperty(idProperty, idValue);
|
||||
}
|
||||
|
||||
final ObjectPath currentPath = path.push(result, entity, idValue);
|
||||
final BeanWrapper<S> wrapper = BeanWrapper.create(instance, conversionService);
|
||||
final S result = wrapper.getBean();
|
||||
|
||||
// Set properties not already set in the constructor
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||
|
||||
// we skip the id property since it was already set
|
||||
if (idProperty != null && idProperty.equals(prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dbo.containsField(prop.getFieldName()) || entity.isConstructorArgument(prop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
accessor.setProperty(prop, getValueInternal(prop, dbo, evaluator, currentPath));
|
||||
wrapper.setProperty(prop, getValueInternal(prop, dbo, evaluator, result));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -294,13 +276,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
|
||||
wrapper.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, new DbRefResolverCallback() {
|
||||
|
||||
DbRefProxyHandler handler = new DefaultDbRefProxyHandler(spELContext, mappingContext,
|
||||
MappingMongoConverter.this);
|
||||
DbRefResolverCallback callback = new DefaultDbRefResolverCallback(dbo, currentPath, evaluator,
|
||||
MappingMongoConverter.this);
|
||||
|
||||
accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
|
||||
@Override
|
||||
public Object resolve(MongoPersistentProperty property) {
|
||||
return getValueInternal(property, dbo, evaluator, parent);
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -348,7 +330,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
typeMapper.writeType(type, dbo);
|
||||
}
|
||||
|
||||
Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).getTarget() : obj;
|
||||
Object target = obj instanceof LazyLoadingProxy ? ((LazyLoadingProxy) obj).initialize() : obj;
|
||||
|
||||
writeInternal(target, dbo, type);
|
||||
}
|
||||
@@ -400,13 +382,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(obj);
|
||||
final BeanWrapper<Object> wrapper = BeanWrapper.create(obj, conversionService);
|
||||
final MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (!dbo.containsField("_id") && null != idProperty) {
|
||||
|
||||
try {
|
||||
Object id = accessor.getProperty(idProperty);
|
||||
Object id = wrapper.getProperty(idProperty, Object.class);
|
||||
dbo.put("_id", idMapper.convertId(id));
|
||||
} catch (ConversionException ignored) {}
|
||||
}
|
||||
@@ -415,11 +397,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
public void doWithPersistentProperty(MongoPersistentProperty prop) {
|
||||
|
||||
if (prop.equals(idProperty) || !prop.isWritable()) {
|
||||
if (prop.equals(idProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object propertyObj = accessor.getProperty(prop);
|
||||
Object propertyObj = wrapper.getProperty(prop);
|
||||
|
||||
if (null != propertyObj) {
|
||||
|
||||
@@ -433,12 +415,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
});
|
||||
|
||||
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
||||
|
||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||
|
||||
MongoPersistentProperty inverseProp = association.getInverse();
|
||||
Object propertyObj = accessor.getProperty(inverseProp);
|
||||
|
||||
Class<?> type = inverseProp.getType();
|
||||
Object propertyObj = wrapper.getProperty(inverseProp, type);
|
||||
if (null != propertyObj) {
|
||||
writePropertyInternal(propertyObj, dbo, inverseProp);
|
||||
}
|
||||
@@ -494,7 +474,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* If we have a LazyLoadingProxy we make sure it is initialized first.
|
||||
*/
|
||||
if (obj instanceof LazyLoadingProxy) {
|
||||
obj = ((LazyLoadingProxy) obj).getTarget();
|
||||
obj = ((LazyLoadingProxy) obj).initialize();
|
||||
}
|
||||
|
||||
// Lookup potential custom target type
|
||||
@@ -508,7 +488,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Object existingValue = accessor.get(prop);
|
||||
BasicDBObject propDbObj = existingValue instanceof BasicDBObject ? (BasicDBObject) existingValue
|
||||
: new BasicDBObject();
|
||||
addCustomTypeKeyIfNecessary(ClassTypeInformation.from(prop.getRawType()), obj, propDbObj);
|
||||
addCustomTypeKeyIfNecessary(type, obj, propDbObj);
|
||||
|
||||
MongoPersistentEntity<?> entity = isSubtype(prop.getType(), obj.getClass()) ? mappingContext
|
||||
.getPersistentEntity(obj.getClass()) : mappingContext.getPersistentEntity(type);
|
||||
@@ -591,7 +571,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 +623,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 +650,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.
|
||||
@@ -691,6 +687,22 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
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.
|
||||
@@ -705,7 +717,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
/**
|
||||
* Adds custom type information to the given {@link DBObject} if necessary. That is if the value is not the same as
|
||||
* the one given. This is usually the case if you store a subtype of the actual declared type of the property.
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param value must not be {@literal null}.
|
||||
* @param dbObject must not be {@literal null}.
|
||||
@@ -771,7 +783,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 +795,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) {
|
||||
@@ -812,8 +824,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
if (target.getClass().equals(idProperty.getType())) {
|
||||
id = target;
|
||||
} else {
|
||||
PersistentPropertyAccessor accessor = targetEntity.getPropertyAccessor(target);
|
||||
id = accessor.getProperty(idProperty);
|
||||
BeanWrapper<Object> wrapper = BeanWrapper.create(target, conversionService);
|
||||
id = wrapper.getProperty(idProperty, Object.class);
|
||||
}
|
||||
|
||||
if (null == id) {
|
||||
@@ -824,14 +836,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
idMapper.convertId(id));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.ValueResolver#getValueInternal(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, com.mongodb.DBObject, org.springframework.data.mapping.model.SpELExpressionEvaluator, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
ObjectPath path) {
|
||||
return new MongoDbPropertyValueProvider(dbo, evaluator, path).getPropertyValue(prop);
|
||||
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
Object parent) {
|
||||
|
||||
return new MongoDbPropertyValueProvider(dbo, evaluator, parent).getPropertyValue(prop);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -839,13 +847,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @param sourceValue must not be {@literal null}.
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, ObjectPath path) {
|
||||
private Object readCollectionOrArray(TypeInformation<?> targetType, BasicDBList sourceValue, Object parent) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null!");
|
||||
Assert.notNull(path, "Object path must not be null!");
|
||||
Assert.notNull(targetType);
|
||||
|
||||
Class<?> collectionType = targetType.getType();
|
||||
|
||||
@@ -866,9 +872,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
if (dbObjItem instanceof DBRef) {
|
||||
items.add(DBRef.class.equals(rawComponentType) ? dbObjItem : read(componentType, readRef((DBRef) dbObjItem),
|
||||
path));
|
||||
parent));
|
||||
} else if (dbObjItem instanceof DBObject) {
|
||||
items.add(read(componentType, (DBObject) dbObjItem, path));
|
||||
items.add(read(componentType, (DBObject) dbObjItem, parent));
|
||||
} else {
|
||||
items.add(getPotentiallyConvertedSimpleRead(dbObjItem, rawComponentType));
|
||||
}
|
||||
@@ -881,15 +887,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* Reads the given {@link DBObject} into a {@link Map}. will recursively resolve nested {@link Map}s as well.
|
||||
*
|
||||
* @param type the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link DBObject}.
|
||||
* @param dbObject must not be {@literal null}
|
||||
* @param path must not be {@literal null}
|
||||
* @param dbObject
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject, ObjectPath path) {
|
||||
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject, Object parent) {
|
||||
|
||||
Assert.notNull(dbObject, "DBObject must not be null!");
|
||||
Assert.notNull(path, "Object path must not be null!");
|
||||
Assert.notNull(dbObject);
|
||||
|
||||
Class<?> mapType = typeMapper.readType(dbObject, type).getType();
|
||||
|
||||
@@ -916,7 +920,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Object value = entry.getValue();
|
||||
|
||||
if (value instanceof DBObject) {
|
||||
map.put(key, read(valueType, (DBObject) value, path));
|
||||
map.put(key, read(valueType, (DBObject) value, parent));
|
||||
} else if (value instanceof DBRef) {
|
||||
map.put(key, DBRef.class.equals(rawValueType) ? value : read(valueType, readRef((DBRef) value)));
|
||||
} else {
|
||||
@@ -928,6 +932,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return map;
|
||||
}
|
||||
|
||||
protected <T> List<?> unwrapList(BasicDBList dbList, TypeInformation<T> targetType) {
|
||||
List<Object> rootList = new ArrayList<Object>();
|
||||
for (int i = 0; i < dbList.size(); i++) {
|
||||
Object obj = dbList.get(i);
|
||||
if (obj instanceof BasicDBList) {
|
||||
rootList.add(unwrapList((BasicDBList) obj, targetType.getComponentType()));
|
||||
} else if (obj instanceof DBObject) {
|
||||
rootList.add(read(targetType, (DBObject) obj));
|
||||
} else {
|
||||
rootList.add(obj);
|
||||
}
|
||||
}
|
||||
return rootList;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.MongoWriter#convertToMongoType(java.lang.Object, org.springframework.data.util.TypeInformation)
|
||||
@@ -1047,24 +1066,24 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
private final DBObjectAccessor source;
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
private final ObjectPath path;
|
||||
private final Object parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
|
||||
* {@link ObjectPath}.
|
||||
* parent object.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param path can be {@literal null}.
|
||||
* @param parent can be {@literal null}.
|
||||
*/
|
||||
public MongoDbPropertyValueProvider(DBObject source, SpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||
public MongoDbPropertyValueProvider(DBObject source, SpELExpressionEvaluator evaluator, Object parent) {
|
||||
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(evaluator);
|
||||
|
||||
this.source = new DBObjectAccessor(source);
|
||||
this.evaluator = evaluator;
|
||||
this.path = path;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1080,7 +1099,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
return null;
|
||||
}
|
||||
|
||||
return readValue(value, property.getTypeInformation(), path);
|
||||
return readValue(value, property.getTypeInformation(), parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,7 +1112,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
private class ConverterAwareSpELExpressionParameterValueProvider extends
|
||||
SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
||||
|
||||
private final ObjectPath path;
|
||||
private final Object parent;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
|
||||
@@ -1103,10 +1122,10 @@ 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, Object parent) {
|
||||
|
||||
super(evaluator, conversionService, delegate);
|
||||
this.path = path;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1115,44 +1134,28 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*/
|
||||
@Override
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
|
||||
return readValue(object, parameter.getType(), path);
|
||||
return readValue(object, parameter.getType(), parent);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T readValue(Object value, TypeInformation<?> type, ObjectPath path) {
|
||||
private <T> T readValue(Object value, TypeInformation<?> type, Object parent) {
|
||||
|
||||
Class<?> rawType = type.getType();
|
||||
|
||||
if (conversions.hasCustomReadTarget(value.getClass(), rawType)) {
|
||||
return (T) conversionService.convert(value, rawType);
|
||||
} else if (value instanceof DBRef) {
|
||||
return potentiallyReadOrResolveDbRef((DBRef) value, type, path, rawType);
|
||||
return (T) (rawType.equals(DBRef.class) ? value : read(type, readRef((DBRef) value), parent));
|
||||
} else if (value instanceof BasicDBList) {
|
||||
return (T) readCollectionOrArray(type, (BasicDBList) value, path);
|
||||
return (T) readCollectionOrArray(type, (BasicDBList) value, parent);
|
||||
} else if (value instanceof DBObject) {
|
||||
return (T) read(type, (DBObject) value, path);
|
||||
return (T) read(type, (DBObject) value, parent);
|
||||
} else {
|
||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T potentiallyReadOrResolveDbRef(DBRef dbref, TypeInformation<?> type, ObjectPath path, Class<?> rawType) {
|
||||
|
||||
if (rawType.equals(DBRef.class)) {
|
||||
return (T) dbref;
|
||||
}
|
||||
|
||||
Object object = dbref == null ? null : path.getPathItem(dbref.getId(), dbref.getRef());
|
||||
|
||||
if (object != null) {
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
return (T) (object != null ? object : read(type, readRef(dbref), path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the fetch operation for the given {@link DBRef}.
|
||||
*
|
||||
|
||||
@@ -25,8 +25,6 @@ import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
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.util.StringUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
@@ -36,7 +34,6 @@ import com.mongodb.DBObject;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
abstract class MongoConverters {
|
||||
|
||||
@@ -163,19 +160,4 @@ abstract class MongoConverters {
|
||||
return source == null ? null : source.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@WritingConverter
|
||||
public static enum TermToStringConverter implements Converter<Term, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String convert(Term source) {
|
||||
return source == null ? null : source.getFormatted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* A path of objects nested into each other. The type allows access to all parent objects currently in creation even
|
||||
* when resolving more nested objects. This allows to avoid re-resolving object instances that are logically equivalent
|
||||
* to already resolved ones.
|
||||
* <p>
|
||||
* An immutable ordered set of target objects for {@link DBObject} to {@link Object} conversions. Object paths can be
|
||||
* constructed by the {@link #toObjectPath(Object)} method and extended via {@link #push(Object)}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
class ObjectPath {
|
||||
|
||||
public static final ObjectPath ROOT = new ObjectPath();
|
||||
|
||||
private final List<ObjectPathItem> items;
|
||||
|
||||
private ObjectPath() {
|
||||
this.items = Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjectPath} from the given parent {@link ObjectPath} by adding the provided
|
||||
* {@link ObjectPathItem} to it.
|
||||
*
|
||||
* @param parent can be {@literal null}.
|
||||
* @param item
|
||||
*/
|
||||
private ObjectPath(ObjectPath parent, ObjectPath.ObjectPathItem item) {
|
||||
|
||||
List<ObjectPath.ObjectPathItem> items = new ArrayList<ObjectPath.ObjectPathItem>(parent.items);
|
||||
items.add(item);
|
||||
|
||||
this.items = Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the {@link ObjectPath} with the given {@link Object} as current object.
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param id must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public ObjectPath push(Object object, MongoPersistentEntity<?> entity, Object id) {
|
||||
|
||||
Assert.notNull(object, "Object must not be null!");
|
||||
Assert.notNull(entity, "MongoPersistentEntity must not be null!");
|
||||
|
||||
ObjectPathItem item = new ObjectPathItem(object, id, entity.getCollection());
|
||||
return new ObjectPath(this, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object with the given id and stored in the given collection if it's contained in the {@link ObjectPath}
|
||||
* .
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @param collection must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public Object getPathItem(Object id, String collection) {
|
||||
|
||||
Assert.notNull(id, "Id must not be null!");
|
||||
Assert.hasText(collection, "Collection name must not be null!");
|
||||
|
||||
for (ObjectPathItem item : items) {
|
||||
|
||||
Object object = item.getObject();
|
||||
|
||||
if (object == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.getIdValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (collection.equals(item.getCollection()) && id.equals(item.getIdValue())) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current object of the {@link ObjectPath} or {@literal null} if the path is empty.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Object getCurrentObject() {
|
||||
return items.isEmpty() ? null : items.get(items.size() - 1).getObject();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if (items.isEmpty()) {
|
||||
return "[empty]";
|
||||
}
|
||||
|
||||
List<String> strings = new ArrayList<String>(items.size());
|
||||
|
||||
for (ObjectPathItem item : items) {
|
||||
strings.add(item.object.toString());
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(strings, " -> ");
|
||||
}
|
||||
|
||||
/**
|
||||
* An item in an {@link ObjectPath}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class ObjectPathItem {
|
||||
|
||||
private final Object object;
|
||||
private final Object idValue;
|
||||
private final String collection;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjectPathItem}.
|
||||
*
|
||||
* @param object
|
||||
* @param idValue
|
||||
* @param collection
|
||||
*/
|
||||
ObjectPathItem(Object object, Object idValue, String collection) {
|
||||
|
||||
this.object = object;
|
||||
this.idValue = idValue;
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public Object getIdValue() {
|
||||
return idValue;
|
||||
}
|
||||
|
||||
public String getCollection() {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,6 @@ import com.mongodb.DBRef;
|
||||
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");
|
||||
|
||||
private enum MetaMapping {
|
||||
FORCE, WHEN_PRESENT, IGNORE;
|
||||
}
|
||||
|
||||
private final ConversionService conversionService;
|
||||
private final MongoConverter converter;
|
||||
@@ -124,61 +119,6 @@ public class QueryMapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps fields used for sorting to the {@link MongoPersistentEntity}s properties. <br />
|
||||
* Also converts properties to their {@code $meta} representation if present.
|
||||
*
|
||||
* @param sortObject
|
||||
* @param entity
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public DBObject getMappedSort(DBObject sortObject, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (sortObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DBObject mappedSort = getMappedObject(sortObject, entity);
|
||||
mapMetaAttributes(mappedSort, entity, MetaMapping.WHEN_PRESENT);
|
||||
return mappedSort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps fields to retrieve to the {@link MongoPersistentEntity}s properties. <br />
|
||||
* Also onverts and potentially adds missing property {@code $meta} representation.
|
||||
*
|
||||
* @param fieldsObject
|
||||
* @param entity
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public DBObject getMappedFields(DBObject fieldsObject, MongoPersistentEntity<?> entity) {
|
||||
|
||||
DBObject mappedFields = fieldsObject != null ? getMappedObject(fieldsObject, entity) : new BasicDBObject();
|
||||
mapMetaAttributes(mappedFields, entity, MetaMapping.FORCE);
|
||||
return mappedFields.keySet().isEmpty() ? null : mappedFields;
|
||||
}
|
||||
|
||||
private void mapMetaAttributes(DBObject source, MongoPersistentEntity<?> entity, MetaMapping metaMapping) {
|
||||
|
||||
if (entity == null || source == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity.hasTextScoreProperty() && !MetaMapping.IGNORE.equals(metaMapping)) {
|
||||
MongoPersistentProperty textScoreProperty = entity.getTextScoreProperty();
|
||||
if (MetaMapping.FORCE.equals(metaMapping)
|
||||
|| (MetaMapping.WHEN_PRESENT.equals(metaMapping) && source.containsField(textScoreProperty.getFieldName()))) {
|
||||
source.putAll(getMappedTextScoreField(textScoreProperty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DBObject getMappedTextScoreField(MongoPersistentProperty property) {
|
||||
return new BasicDBObject(property.getFieldName(), META_TEXT_SCORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the mapped object value for given field out of rawValue taking nested {@link Keyword}s into account
|
||||
*
|
||||
@@ -334,8 +274,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = documentField.getPropertyEntity();
|
||||
return entity.hasIdProperty()
|
||||
&& (type.equals(DBRef.class) || entity.getIdProperty().getActualType().isAssignableFrom(type));
|
||||
return entity.hasIdProperty() && entity.getIdProperty().getActualType().isAssignableFrom(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,16 +322,10 @@ public class QueryMapper {
|
||||
*/
|
||||
protected Object convertAssociation(Object source, MongoPersistentProperty property) {
|
||||
|
||||
if (property == null || source == null || source instanceof DBObject) {
|
||||
if (property == null || source == null || source instanceof DBRef || source instanceof DBObject) {
|
||||
return source;
|
||||
}
|
||||
|
||||
if (source instanceof DBRef) {
|
||||
|
||||
DBRef ref = (DBRef) source;
|
||||
return new DBRef(ref.getDB(), ref.getRef(), convertId(ref.getId()));
|
||||
}
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
BasicDBList result = new BasicDBList();
|
||||
for (Object element : (Iterable<?>) source) {
|
||||
@@ -464,13 +397,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -792,7 +732,7 @@ public class QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
public String getMappedKey() {
|
||||
return path == null ? name : path.toDotPath(isAssociation() ? getAssociationConverter() : getPropertyConverter());
|
||||
return path == null ? name : path.toDotPath(getPropertyConverter());
|
||||
}
|
||||
|
||||
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
|
||||
@@ -844,56 +784,5 @@ public class QueryMapper {
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return PropertyToFieldNameConverter.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Converter} to use for creating the mapped key of an association. Default implementation is
|
||||
* {@link AssociationConverter}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new AssociationConverter(getAssociation());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converter to skip all properties after an association property was rendered.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
protected static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final MongoPersistentProperty property;
|
||||
private boolean associationFound;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
this.property = association.getInverse();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
|
||||
if (associationFound) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (property.equals(source)) {
|
||||
associationFound = true;
|
||||
}
|
||||
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,48 +194,47 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return new UpdatePropertyConverter(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getAssociationConverter()
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new UpdateAssociationConverter(getAssociation(), key);
|
||||
return isAssociation() ? new AssociationConverter(getAssociation()) : new UpdatePropertyConverter(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special mapper handling positional parameter {@literal $} within property names.
|
||||
* Converter to skip all properties after an association property was rendered.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class UpdateKeyMapper {
|
||||
private static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
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();
|
||||
}
|
||||
private final MongoPersistentProperty property;
|
||||
private boolean associationFound;
|
||||
|
||||
/**
|
||||
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||
|
||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
this.property = association.getInverse();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
|
||||
if (associationFound) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (property.equals(source)) {
|
||||
associationFound = true;
|
||||
}
|
||||
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,11 +242,10 @@ public class UpdateMapper extends QueryMapper {
|
||||
* contained in the source update key.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final UpdateKeyMapper mapper;
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
||||
@@ -258,7 +256,8 @@ public class UpdateMapper extends QueryMapper {
|
||||
|
||||
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
||||
|
||||
this.mapper = new UpdateKeyMapper(updateKey);
|
||||
this.iterator = Arrays.asList(updateKey.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -267,37 +266,9 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty property) {
|
||||
return mapper.mapPropertyName(property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Converter} retaining positional parameter {@literal $} for {@link Association}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
protected static class UpdateAssociationConverter extends AssociationConverter {
|
||||
|
||||
private final UpdateKeyMapper mapper;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
|
||||
|
||||
super(association);
|
||||
this.mapper = new UpdateKeyMapper(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
return super.convert(source) == null ? null : mapper.mapPropertyName(source);
|
||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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 org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Internal API to trigger the resolution of properties.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface ValueResolver {
|
||||
|
||||
/**
|
||||
* Resolves the value for the given {@link MongoPersistentProperty} within the given {@link DBObject} using the given
|
||||
* {@link SpELExpressionEvaluator} and {@link ObjectPath}.
|
||||
*
|
||||
* @param prop
|
||||
* @param dbo
|
||||
* @param evaluator
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
ObjectPath parent);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* Represents a geospatial box value.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Box}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class Box extends org.springframework.data.geo.Box implements Shape {
|
||||
|
||||
public static final String COMMAND = "$box";
|
||||
|
||||
public Box(Point lowerLeft, Point upperRight) {
|
||||
super(lowerLeft, upperRight);
|
||||
}
|
||||
|
||||
public Box(double[] lowerLeft, double[] upperRight) {
|
||||
super(lowerLeft, upperRight);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||
*/
|
||||
public List<? extends Object> asList() {
|
||||
|
||||
List<List<Double>> list = new ArrayList<List<Double>>();
|
||||
|
||||
list.add(Arrays.asList(getFirst().getX(), getFirst().getY()));
|
||||
list.add(Arrays.asList(getSecond().getX(), getSecond().getY()));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public org.springframework.data.mongodb.core.geo.Point getLowerLeft() {
|
||||
return new org.springframework.data.mongodb.core.geo.Point(getFirst());
|
||||
}
|
||||
|
||||
public org.springframework.data.mongodb.core.geo.Point getUpperRight() {
|
||||
return new org.springframework.data.mongodb.core.geo.Point(getSecond());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||
*/
|
||||
public String getCommand() {
|
||||
return COMMAND;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.List;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents a geospatial circle value.
|
||||
* <p>
|
||||
* Note: We deliberately do not extend org.springframework.data.geo.Circle because introducing it's distance concept
|
||||
* would break the clients that use the old Circle API.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Circle}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
*/
|
||||
@Deprecated
|
||||
public class Circle implements Shape {
|
||||
|
||||
public static final String COMMAND = "$center";
|
||||
|
||||
private final Point center;
|
||||
private final double radius;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Circle} from the given {@link Point} and radius.
|
||||
*
|
||||
* @param center must not be {@literal null}.
|
||||
* @param radius must be greater or equal to zero.
|
||||
*/
|
||||
@PersistenceConstructor
|
||||
public Circle(Point center, double radius) {
|
||||
|
||||
Assert.notNull(center);
|
||||
Assert.isTrue(radius >= 0, "Radius must not be negative!");
|
||||
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Circle} from the given coordinates and radius as {@link Distance} with a
|
||||
* {@link Metrics#NEUTRAL}.
|
||||
*
|
||||
* @param centerX
|
||||
* @param centerY
|
||||
* @param radius must be greater or equal to zero.
|
||||
*/
|
||||
public Circle(double centerX, double centerY, double radius) {
|
||||
this(new Point(centerX, centerY), radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the center of the {@link Circle}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Point getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the radius of the {@link Circle}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public double getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||
*/
|
||||
public List<Object> asList() {
|
||||
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
result.add(Arrays.asList(getCenter().getX(), getCenter().getY()));
|
||||
result.add(getRadius());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||
*/
|
||||
public String getCommand() {
|
||||
return COMMAND;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Circle [center=%s, radius=%f]", center, radius);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Circle that = (Circle) obj;
|
||||
|
||||
return this.center.equals(that.center) && this.radius == that.radius;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result += 31 * center.hashCode();
|
||||
result += 31 * radius;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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;
|
||||
|
||||
/**
|
||||
* Value object to create custom {@link Metric}s on the fly.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metric}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class CustomMetric extends org.springframework.data.geo.CustomMetric implements Metric {
|
||||
|
||||
/**
|
||||
* Creates a custom {@link Metric} using the given multiplier.
|
||||
*
|
||||
* @param multiplier
|
||||
*/
|
||||
public CustomMetric(double multiplier) {
|
||||
super(multiplier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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 org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
|
||||
/**
|
||||
* Value object to represent distances in a given metric.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Distance}. This class is scheduled to
|
||||
* be removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class Distance extends org.springframework.data.geo.Distance {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Distance}.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public Distance(double value) {
|
||||
this(value, Metrics.NEUTRAL);
|
||||
}
|
||||
|
||||
public Distance(double value, Metric metric) {
|
||||
super(value, metric);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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 org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* Custom {@link Page} to carry the average distance retrieved from the {@link GeoResults} the {@link GeoPage} is set up
|
||||
* from.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoPage}. This class is scheduled to
|
||||
* be removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class GeoPage<T> extends org.springframework.data.geo.GeoPage<T> {
|
||||
|
||||
private static final long serialVersionUID = 23421312312412L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}.
|
||||
*
|
||||
* @param content must not be {@literal null}.
|
||||
*/
|
||||
public GeoPage(GeoResults<T> results) {
|
||||
super(results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoPage} from the given {@link GeoResults}, {@link Pageable} and total.
|
||||
*
|
||||
* @param results must not be {@literal null}.
|
||||
* @param pageable must not be {@literal null}.
|
||||
* @param total
|
||||
*/
|
||||
public GeoPage(GeoResults<T> results, Pageable pageable, long total) {
|
||||
super(results, pageable, total);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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;
|
||||
|
||||
/**
|
||||
* Calue object capturing some arbitrary object plus a distance.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoResult}. This class is scheduled to
|
||||
* be removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class GeoResult<T> extends org.springframework.data.geo.GeoResult<T> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoResult} for the given content and distance.
|
||||
*
|
||||
* @param content must not be {@literal null}.
|
||||
* @param distance must not be {@literal null}.
|
||||
*/
|
||||
public GeoResult(T content, Distance distance) {
|
||||
super(content, distance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResult;
|
||||
import org.springframework.data.geo.Metric;
|
||||
|
||||
/**
|
||||
* Value object to capture {@link GeoResult}s as well as the average distance they have.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.GeoResults}. This class is scheduled
|
||||
* to be removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class GeoResults<T> extends org.springframework.data.geo.GeoResults<T> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoResults} instance manually calculating the average distance from the distance values of the
|
||||
* given {@link GeoResult}s.
|
||||
*
|
||||
* @param results must not be {@literal null}.
|
||||
*/
|
||||
public GeoResults(List<? extends GeoResult<T>> results) {
|
||||
super(results);
|
||||
}
|
||||
|
||||
public GeoResults(List<? extends GeoResult<T>> results, Metric metric) {
|
||||
super(results, metric);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GeoResults} instance from the given {@link GeoResult}s and average distance.
|
||||
*
|
||||
* @param results must not be {@literal null}.
|
||||
* @param averageDistance
|
||||
*/
|
||||
@PersistenceConstructor
|
||||
public GeoResults(List<? extends GeoResult<T>> results, Distance averageDistance) {
|
||||
super(results, averageDistance);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2011-2014 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
|
||||
* 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,
|
||||
@@ -13,16 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
/**
|
||||
* Interface for {@link Metric}s that can be applied to a base scale.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metric}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public interface DbRefProxyHandler {
|
||||
|
||||
Object populateId(MongoPersistentProperty property, DBRef source, Object proxy);
|
||||
}
|
||||
@Deprecated
|
||||
public interface Metric extends org.springframework.data.geo.Metric {}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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 org.springframework.data.mongodb.core.query.NearQuery;
|
||||
|
||||
/**
|
||||
* Commonly used {@link Metrics} for {@link NearQuery}s.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Metrics}. This class is scheduled to
|
||||
* be removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public enum Metrics implements Metric {
|
||||
|
||||
KILOMETERS(org.springframework.data.geo.Metrics.KILOMETERS.getMultiplier()), //
|
||||
MILES(org.springframework.data.geo.Metrics.MILES.getMultiplier()), //
|
||||
NEUTRAL(org.springframework.data.geo.Metrics.NEUTRAL.getMultiplier()); //
|
||||
|
||||
private final double multiplier;
|
||||
|
||||
private Metrics(double multiplier) {
|
||||
this.multiplier = multiplier;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Metric#getMultiplier()
|
||||
*/
|
||||
public double getMultiplier() {
|
||||
return multiplier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.annotation.PersistenceConstructor;
|
||||
|
||||
/**
|
||||
* Represents a geospatial point value.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Point}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class Point extends org.springframework.data.geo.Point {
|
||||
|
||||
@PersistenceConstructor
|
||||
public Point(double x, double y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
public Point(org.springframework.data.geo.Point point) {
|
||||
super(point);
|
||||
}
|
||||
|
||||
public double[] asArray() {
|
||||
return new double[] { getX(), getY() };
|
||||
}
|
||||
|
||||
public List<Double> asList() {
|
||||
return asList(this);
|
||||
}
|
||||
|
||||
public static List<Double> asList(org.springframework.data.geo.Point point) {
|
||||
return Arrays.asList(point.getX(), point.getY());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* Simple value object to represent a {@link Polygon}.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Point}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public class Polygon extends org.springframework.data.geo.Polygon implements Shape {
|
||||
|
||||
public static final String COMMAND = "$polygon";
|
||||
|
||||
/**
|
||||
* Creates a new {@link Polygon} for the given Points.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param others
|
||||
*/
|
||||
public <P extends Point> Polygon(P x, P y, P z, P... others) {
|
||||
super(x, y, z, others);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Polygon} for the given Points.
|
||||
*
|
||||
* @param points
|
||||
*/
|
||||
public <P extends Point> Polygon(List<P> points) {
|
||||
super(points);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||
*/
|
||||
public String getCommand() {
|
||||
return COMMAND;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||
*/
|
||||
@Override
|
||||
public List<? extends Object> asList() {
|
||||
return asList(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link List} of x,y-coordinate tuples of {@link Point}s from the given {@link Polygon}.
|
||||
*
|
||||
* @param polygon
|
||||
* @return
|
||||
*/
|
||||
public static List<? extends Object> asList(org.springframework.data.geo.Polygon polygon) {
|
||||
|
||||
List<Point> points = polygon.getPoints();
|
||||
List<List<Double>> tuples = new ArrayList<List<Double>>(points.size());
|
||||
|
||||
for (Point point : points) {
|
||||
tuples.add(Arrays.asList(point.getX(), point.getY()));
|
||||
}
|
||||
|
||||
return tuples;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2011-2014 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;
|
||||
|
||||
/**
|
||||
* Common interface for all shapes. Allows building MongoDB representations of them.
|
||||
*
|
||||
* @deprecated As of release 1.5, replaced by {@link org.springframework.data.geo.Shape}. This class is scheduled to be
|
||||
* removed in the next major release.
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Deprecated
|
||||
public interface Shape extends org.springframework.data.geo.Shape {
|
||||
|
||||
/**
|
||||
* Returns the {@link Shape} as a list of usually {@link Double} or {@link List}s of {@link Double}s. Wildcard bound
|
||||
* to allow implementations to return a more concrete element type.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<? extends Object> asList();
|
||||
|
||||
/**
|
||||
* Returns the command to be used to create the {@literal $within} criterion.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getCommand();
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -31,6 +30,7 @@ import org.springframework.util.Assert;
|
||||
* @author Thomas Darimont
|
||||
* @since 1.5
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class Sphere implements Shape {
|
||||
|
||||
public static final String COMMAND = "$centerSphere";
|
||||
@@ -73,13 +73,23 @@ public class Sphere implements Shape {
|
||||
this(circle.getCenter(), circle.getRadius());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Sphere from the given {@link Circle}.
|
||||
*
|
||||
* @param circle
|
||||
*/
|
||||
@Deprecated
|
||||
public Sphere(org.springframework.data.mongodb.core.geo.Circle circle) {
|
||||
this(circle.getCenter(), circle.getRadius());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the center of the {@link Circle}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Point getCenter() {
|
||||
return new Point(this.center);
|
||||
public org.springframework.data.mongodb.core.geo.Point getCenter() {
|
||||
return new org.springframework.data.mongodb.core.geo.Point(this.center);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,21 +141,20 @@ public class Sphere implements Shape {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Shape} as a list of usually {@link Double} or {@link List}s of {@link Double}s. Wildcard bound
|
||||
* to allow implementations to return a more concrete element type.
|
||||
*
|
||||
* @return
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#asList()
|
||||
*/
|
||||
@Override
|
||||
public List<? extends Object> asList() {
|
||||
return Arrays.asList(Arrays.asList(center.getX(), center.getY()), this.radius.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command to be used to create the {@literal $within} criterion.
|
||||
*
|
||||
* @return
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.Shape#getCommand()
|
||||
*/
|
||||
@Override
|
||||
public String getCommand() {
|
||||
return COMMAND;
|
||||
}
|
||||
|
||||
@@ -129,10 +129,7 @@ public @interface CompoundIndex {
|
||||
* stored in.
|
||||
*
|
||||
* @return
|
||||
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||
* result in broken definitions. Will be removed in 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
String collection() default "";
|
||||
|
||||
/**
|
||||
@@ -143,4 +140,14 @@ public @interface CompoundIndex {
|
||||
*/
|
||||
boolean background() default false;
|
||||
|
||||
/**
|
||||
* Configures the number of seconds after which the collection should expire. Defaults to -1 for no expiry.
|
||||
*
|
||||
* @deprecated TTL cannot be defined for {@link CompoundIndex} having more than one field as key. Will be removed in
|
||||
* 1.6.
|
||||
* @see http://docs.mongodb.org/manual/tutorial/expire-data/
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
int expireAfterSeconds() default -1;
|
||||
}
|
||||
|
||||
@@ -85,10 +85,7 @@ public @interface GeoSpatialIndexed {
|
||||
* Name of the collection in which to create the index.
|
||||
*
|
||||
* @return
|
||||
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||
* result in broken definitions. Will be removed in 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
String collection() default "";
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,17 +35,7 @@ import com.mongodb.DBObject;
|
||||
public class Index implements IndexDefinition {
|
||||
|
||||
public enum Duplicates {
|
||||
RETAIN, //
|
||||
|
||||
/**
|
||||
* Dropping Duplicates was removed in MongoDB Server 2.8.0-rc0.
|
||||
* <p>
|
||||
* See https://jira.mongodb.org/browse/SERVER-14710
|
||||
*
|
||||
* @deprecated since 1.7.
|
||||
*/
|
||||
@Deprecated//
|
||||
DROP
|
||||
RETAIN, DROP
|
||||
}
|
||||
|
||||
private final Map<String, Direction> fieldSpec = new LinkedHashMap<String, Direction>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2013 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,33 +24,22 @@ import org.springframework.util.ObjectUtils;
|
||||
* Value object for an index field.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class IndexField {
|
||||
|
||||
enum Type {
|
||||
GEO, TEXT, DEFAULT;
|
||||
}
|
||||
|
||||
private final String key;
|
||||
private final Direction direction;
|
||||
private final Type type;
|
||||
private final Float weight;
|
||||
private final boolean isGeo;
|
||||
|
||||
private IndexField(String key, Direction direction, Type type) {
|
||||
this(key, direction, type, Float.NaN);
|
||||
}
|
||||
|
||||
private IndexField(String key, Direction direction, Type type, Float weight) {
|
||||
private IndexField(String key, Direction direction, boolean isGeo) {
|
||||
|
||||
Assert.hasText(key);
|
||||
Assert.isTrue(direction != null ^ (Type.GEO.equals(type) || Type.TEXT.equals(type)));
|
||||
Assert.isTrue(direction != null ^ isGeo);
|
||||
|
||||
this.key = key;
|
||||
this.direction = direction;
|
||||
this.type = type == null ? Type.DEFAULT : type;
|
||||
this.weight = weight == null ? Float.NaN : weight;
|
||||
this.isGeo = isGeo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,12 +53,12 @@ public final class IndexField {
|
||||
@Deprecated
|
||||
public static IndexField create(String key, Order order) {
|
||||
Assert.notNull(order);
|
||||
return new IndexField(key, order.toDirection(), Type.DEFAULT);
|
||||
return new IndexField(key, order.toDirection(), false);
|
||||
}
|
||||
|
||||
public static IndexField create(String key, Direction order) {
|
||||
Assert.notNull(order);
|
||||
return new IndexField(key, order, Type.DEFAULT);
|
||||
return new IndexField(key, order, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,16 +68,7 @@ public final class IndexField {
|
||||
* @return
|
||||
*/
|
||||
public static IndexField geo(String key) {
|
||||
return new IndexField(key, null, Type.GEO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text {@link IndexField} for the given key.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public static IndexField text(String key, Float weight) {
|
||||
return new IndexField(key, null, Type.TEXT, weight);
|
||||
return new IndexField(key, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,20 +101,10 @@ public final class IndexField {
|
||||
/**
|
||||
* Returns whether the {@link IndexField} is a geo index field.
|
||||
*
|
||||
* @return true if type is {@link Type#GEO}.
|
||||
* @return the isGeo
|
||||
*/
|
||||
public boolean isGeo() {
|
||||
return Type.GEO.equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wheter the {@link IndexField} is a text index field.
|
||||
*
|
||||
* @return true if type is {@link Type#TEXT}
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean isText() {
|
||||
return Type.TEXT.equals(type);
|
||||
return isGeo;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,7 +125,7 @@ public final class IndexField {
|
||||
IndexField that = (IndexField) obj;
|
||||
|
||||
return this.key.equals(that.key) && ObjectUtils.nullSafeEquals(this.direction, that.direction)
|
||||
&& this.type == that.type;
|
||||
&& this.isGeo == that.isGeo;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -168,8 +138,7 @@ public final class IndexField {
|
||||
int result = 17;
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(key);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(direction);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(type);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(weight);
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(isGeo);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -179,7 +148,6 @@ public final class IndexField {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("IndexField [ key: %s, direction: %s, type: %s, weight: %s]", key, direction, type, weight);
|
||||
return String.format("IndexField [ key: %s, direction: %s, isGeo: %s]", key, direction, isGeo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2011 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,11 +23,6 @@ import java.util.List;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class IndexInfo {
|
||||
|
||||
private final List<IndexField> indexFields;
|
||||
@@ -36,30 +31,14 @@ public class IndexInfo {
|
||||
private final boolean unique;
|
||||
private final boolean dropDuplicates;
|
||||
private final boolean sparse;
|
||||
private final String language;
|
||||
|
||||
/**
|
||||
* @deprecated Will be removed in 1.7. Please use {@link #IndexInfo(List, String, boolean, boolean, boolean, String)}
|
||||
* @param indexFields
|
||||
* @param name
|
||||
* @param unique
|
||||
* @param dropDuplicates
|
||||
* @param sparse
|
||||
*/
|
||||
@Deprecated
|
||||
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse) {
|
||||
this(indexFields, name, unique, dropDuplicates, sparse, "");
|
||||
}
|
||||
|
||||
public IndexInfo(List<IndexField> indexFields, String name, boolean unique, boolean dropDuplicates, boolean sparse,
|
||||
String language) {
|
||||
|
||||
this.indexFields = Collections.unmodifiableList(indexFields);
|
||||
this.name = name;
|
||||
this.unique = unique;
|
||||
this.dropDuplicates = dropDuplicates;
|
||||
this.sparse = sparse;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,23 +84,14 @@ public class IndexInfo {
|
||||
return sparse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndexInfo [indexFields=" + indexFields + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
|
||||
+ dropDuplicates + ", sparse=" + sparse + ", language=" + language + "]";
|
||||
+ dropDuplicates + ", sparse=" + sparse + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (dropDuplicates ? 1231 : 1237);
|
||||
@@ -129,7 +99,6 @@ public class IndexInfo {
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + (sparse ? 1231 : 1237);
|
||||
result = prime * result + (unique ? 1231 : 1237);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(language);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -168,9 +137,6 @@ public class IndexInfo {
|
||||
if (unique != other.unique) {
|
||||
return false;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(language, other.language)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,13 +108,10 @@ public @interface Indexed {
|
||||
boolean useGeneratedName() default false;
|
||||
|
||||
/**
|
||||
* Collection name for index to be created on.
|
||||
* Colleciton name for index to be created on.
|
||||
*
|
||||
* @return
|
||||
* @deprecated The collection name is derived from the domain type. Fixing the collection via this attribute might
|
||||
* result in broken definitions. Will be removed in 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
String collection() default "";
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +130,8 @@ public class MongoPersistentEntityIndexCreator implements
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.mongodb.core.index;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -29,9 +28,6 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
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;
|
||||
import org.springframework.data.mongodb.core.index.TextIndexDefinition.TextIndexedFieldSpec;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
@@ -96,7 +92,6 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
final List<IndexDefinitionHolder> indexInformation = new ArrayList<MongoPersistentEntityIndexResolver.IndexDefinitionHolder>();
|
||||
indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions("", root.getCollection(), root));
|
||||
indexInformation.addAll(potentiallyCreateTextIndexDefinition(root));
|
||||
|
||||
final CycleGuard guard = new CycleGuard();
|
||||
|
||||
@@ -192,86 +187,6 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
return createCompoundIndexDefinitions(dotPath, collection, entity);
|
||||
}
|
||||
|
||||
private Collection<? extends IndexDefinitionHolder> potentiallyCreateTextIndexDefinition(MongoPersistentEntity<?> root) {
|
||||
|
||||
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());
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
}
|
||||
|
||||
TextIndexDefinition indexDefinition = indexDefinitionBuilder.build();
|
||||
|
||||
if (!indexDefinition.hasFieldSpec()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
IndexDefinitionHolder holder = new IndexDefinitionHolder("", indexDefinition, root.getCollection());
|
||||
return Collections.singletonList(holder);
|
||||
|
||||
}
|
||||
|
||||
private void appendTextIndexInformation(final String dotPath,
|
||||
final TextIndexDefinitionBuilder indexDefinitionBuilder, final MongoPersistentEntity<?> entity,
|
||||
final TextIndexIncludeOptions includeOptions, final CycleGuard guard) {
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
guard.protect(persistentProperty, dotPath);
|
||||
|
||||
if (persistentProperty.isExplicitLanguageProperty() && !StringUtils.hasText(dotPath)) {
|
||||
indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName());
|
||||
}
|
||||
|
||||
TextIndexed indexed = persistentProperty.findAnnotation(TextIndexed.class);
|
||||
|
||||
if (includeOptions.isForce() || indexed != null || persistentProperty.isEntity()) {
|
||||
|
||||
String propertyDotPath = (StringUtils.hasText(dotPath) ? dotPath + "." : "")
|
||||
+ persistentProperty.getFieldName();
|
||||
|
||||
Float weight = indexed != null ? indexed.weight()
|
||||
: (includeOptions.getParentFieldSpec() != null ? includeOptions.getParentFieldSpec().getWeight() : 1.0F);
|
||||
|
||||
if (persistentProperty.isEntity()) {
|
||||
|
||||
TextIndexIncludeOptions optionsForNestedType = includeOptions;
|
||||
if (!IncludeStrategy.FORCE.equals(includeOptions.getStrategy()) && indexed != null) {
|
||||
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);
|
||||
} catch (InvalidDataAccessApiUsageException e) {
|
||||
LOGGER.warn(
|
||||
String.format("Potentially invald index structure discovered. Breaking operation for %s.",
|
||||
entity.getName()), e);
|
||||
}
|
||||
} else if (includeOptions.isForce() || indexed != null) {
|
||||
indexDefinitionBuilder.onField(propertyDotPath, weight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link IndexDefinition} wrapped in {@link IndexDefinitionHolder} for {@link CompoundIndexes} of given type.
|
||||
*
|
||||
@@ -324,6 +239,16 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexDefinition.background();
|
||||
}
|
||||
|
||||
int ttl = index.expireAfterSeconds();
|
||||
|
||||
if (ttl >= 0) {
|
||||
if (indexDefinition.getIndexKeys().keySet().size() > 1) {
|
||||
LOGGER.warn("TTL is not supported for compound index with more than one key. TTL={} will be ignored.", ttl);
|
||||
} else {
|
||||
indexDefinition.expire(ttl, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
String collection = StringUtils.hasText(index.collection()) ? index.collection() : fallbackCollection;
|
||||
return new IndexDefinitionHolder(dotPath, indexDefinition, collection);
|
||||
}
|
||||
@@ -466,8 +391,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());
|
||||
}
|
||||
@@ -640,41 +566,4 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
return indexDefinition.getIndexOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
static class TextIndexIncludeOptions {
|
||||
|
||||
enum IncludeStrategy {
|
||||
FORCE, DEFAULT;
|
||||
}
|
||||
|
||||
private final IncludeStrategy strategy;
|
||||
|
||||
private final TextIndexedFieldSpec parentFieldSpec;
|
||||
|
||||
public TextIndexIncludeOptions(IncludeStrategy strategy, TextIndexedFieldSpec parentFieldSpec) {
|
||||
this.strategy = strategy;
|
||||
this.parentFieldSpec = parentFieldSpec;
|
||||
}
|
||||
|
||||
public TextIndexIncludeOptions(IncludeStrategy strategy) {
|
||||
this(strategy, null);
|
||||
}
|
||||
|
||||
public IncludeStrategy getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
public TextIndexedFieldSpec getParentFieldSpec() {
|
||||
return parentFieldSpec;
|
||||
}
|
||||
|
||||
public boolean isForce() {
|
||||
return IncludeStrategy.FORCE.equals(strategy);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.index;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* {@link IndexDefinition} to span multiple keys for text search.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
public class TextIndexDefinition implements IndexDefinition {
|
||||
|
||||
private String name;
|
||||
private Set<TextIndexedFieldSpec> fieldSpecs;
|
||||
private String defaultLanguage;
|
||||
private String languageOverride;
|
||||
|
||||
TextIndexDefinition() {
|
||||
fieldSpecs = new LinkedHashSet<TextIndexedFieldSpec>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TextIndexDefinition} for all fields in the document.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TextIndexDefinition forAllFields() {
|
||||
return new TextIndexDefinitionBuilder().onAllFields().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link TextIndexDefinitionBuilder} to create {@link TextIndexDefinition}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TextIndexDefinitionBuilder builder() {
|
||||
return new TextIndexDefinitionBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldSpec
|
||||
*/
|
||||
public void addFieldSpec(TextIndexedFieldSpec fieldSpec) {
|
||||
this.fieldSpecs.add(fieldSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldSpecs
|
||||
*/
|
||||
public void addFieldSpecs(Collection<TextIndexedFieldSpec> fieldSpecs) {
|
||||
this.fieldSpecs.addAll(fieldSpecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the {@link TextIndexDefinition} has fields assigned.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasFieldSpec() {
|
||||
return !fieldSpecs.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexKeys()
|
||||
*/
|
||||
@Override
|
||||
public DBObject getIndexKeys() {
|
||||
|
||||
DBObject keys = new BasicDBObject();
|
||||
for (TextIndexedFieldSpec fieldSpec : fieldSpecs) {
|
||||
keys.put(fieldSpec.fieldname, "text");
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexOptions()
|
||||
*/
|
||||
@Override
|
||||
public DBObject getIndexOptions() {
|
||||
|
||||
DBObject options = new BasicDBObject();
|
||||
if (StringUtils.hasText(name)) {
|
||||
options.put("name", name);
|
||||
}
|
||||
if (StringUtils.hasText(defaultLanguage)) {
|
||||
options.put("default_language", defaultLanguage);
|
||||
}
|
||||
|
||||
BasicDBObject weightsDbo = new BasicDBObject();
|
||||
for (TextIndexedFieldSpec fieldSpec : fieldSpecs) {
|
||||
if (fieldSpec.isWeighted()) {
|
||||
weightsDbo.put(fieldSpec.getFieldname(), fieldSpec.getWeight());
|
||||
}
|
||||
}
|
||||
|
||||
if (!weightsDbo.isEmpty()) {
|
||||
options.put("weights", weightsDbo);
|
||||
}
|
||||
if (StringUtils.hasText(languageOverride)) {
|
||||
options.put("language_override", languageOverride);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
public static class TextIndexedFieldSpec {
|
||||
|
||||
private final String fieldname;
|
||||
private final Float weight;
|
||||
|
||||
/**
|
||||
* Create new {@link TextIndexedFieldSpec} for given fieldname without any weight.
|
||||
*
|
||||
* @param fieldname
|
||||
*/
|
||||
public TextIndexedFieldSpec(String fieldname) {
|
||||
this(fieldname, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link TextIndexedFieldSpec} for given fieldname and weight.
|
||||
*
|
||||
* @param fieldname
|
||||
* @param weight
|
||||
*/
|
||||
public TextIndexedFieldSpec(String fieldname, Float weight) {
|
||||
|
||||
Assert.hasText(fieldname, "Text index field cannot be blank.");
|
||||
this.fieldname = fieldname;
|
||||
this.weight = weight != null ? weight : 1.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fieldname associated with the {@link TextIndexedFieldSpec}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFieldname() {
|
||||
return fieldname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the weight associated with the {@link TextIndexedFieldSpec}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if {@link #weight} has a value that is a valid number.
|
||||
*/
|
||||
public boolean isWeighted() {
|
||||
return this.weight != null && this.weight.compareTo(1.0F) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(fieldname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof TextIndexedFieldSpec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextIndexedFieldSpec other = (TextIndexedFieldSpec) obj;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(this.fieldname, other.fieldname);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TextIndexDefinitionBuilder} helps defining options for creating {@link TextIndexDefinition}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
public static class TextIndexDefinitionBuilder {
|
||||
|
||||
private TextIndexDefinition instance;
|
||||
private static final TextIndexedFieldSpec ALL_FIELDS = new TextIndexedFieldSpec("$**");
|
||||
|
||||
public TextIndexDefinitionBuilder() {
|
||||
this.instance = new TextIndexDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the name to be used when creating the index in the store.
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder named(String name) {
|
||||
this.instance.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the index to span all fields using wilcard. <br/>
|
||||
* <strong>NOTE</strong> {@link TextIndexDefinition} cannot contain any other fields when defined with wildcard.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder onAllFields() {
|
||||
|
||||
if (!instance.fieldSpecs.isEmpty()) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot add wildcard fieldspect to non empty.");
|
||||
}
|
||||
|
||||
this.instance.fieldSpecs.add(ALL_FIELDS);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include given fields with default weight.
|
||||
*
|
||||
* @param fieldnames
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder onFields(String... fieldnames) {
|
||||
|
||||
for (String fieldname : fieldnames) {
|
||||
onField(fieldname);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include given field with default weight.
|
||||
*
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder onField(String fieldname) {
|
||||
return onField(fieldname, 1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include given field with weight.
|
||||
*
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder onField(String fieldname, Float weight) {
|
||||
|
||||
if (this.instance.fieldSpecs.contains(ALL_FIELDS)) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format("Cannot add %s to field spec for all fields.",
|
||||
fieldname));
|
||||
}
|
||||
|
||||
this.instance.fieldSpecs.add(new TextIndexedFieldSpec(fieldname, weight));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the default language to be used when indexing documents.
|
||||
*
|
||||
* @param language
|
||||
* @see http://docs.mongodb.org/manual/tutorial/specify-language-for-text-index/#specify-default-language-text-index
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder withDefaultLanguage(String language) {
|
||||
|
||||
this.instance.defaultLanguage = language;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define field for language override.
|
||||
*
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
public TextIndexDefinitionBuilder withLanguageOverride(String fieldname) {
|
||||
|
||||
if (StringUtils.hasText(this.instance.languageOverride)) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format(
|
||||
"Cannot set language override on %s as it is already defined on %s.", fieldname,
|
||||
this.instance.languageOverride));
|
||||
}
|
||||
|
||||
this.instance.languageOverride = fieldname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextIndexDefinition build() {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.index;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* {@link TextIndexed} marks a field to be part of the text index. As there can be only one text index per collection
|
||||
* all fields marked with {@link TextIndexed} are combined into one single index. <br />
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TextIndexed {
|
||||
|
||||
/**
|
||||
* Defines the significance of the filed relative to other indexed fields. The value directly influences the documents
|
||||
* score. <br/>
|
||||
* Defaulted to {@literal 1.0}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
float weight() default 1.0F;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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.
|
||||
@@ -35,11 +35,9 @@ import org.springframework.data.mongodb.MongoCollectionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -49,45 +47,36 @@ import org.springframework.util.StringUtils;
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, MongoPersistentProperty> implements
|
||||
MongoPersistentEntity<T>, ApplicationContextAware {
|
||||
|
||||
private static final String AMBIGUOUS_FIELD_MAPPING = "Ambiguous field mapping detected! Both %s and %s map to the same field name %s! Disambiguate using @Field annotation!";
|
||||
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
private final String collection;
|
||||
private final String language;
|
||||
|
||||
private final SpelExpressionParser parser;
|
||||
private final StandardEvaluationContext context;
|
||||
private final Expression expression;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicMongoPersistentEntity} with the given {@link TypeInformation}. Will default the
|
||||
* collection name to the entities simple type name.
|
||||
*
|
||||
* @param typeInformation must not be {@literal null}.
|
||||
* @param typeInformation
|
||||
*/
|
||||
public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
|
||||
super(typeInformation, MongoPersistentPropertyComparator.INSTANCE);
|
||||
|
||||
this.parser = new SpelExpressionParser();
|
||||
this.context = new StandardEvaluationContext();
|
||||
|
||||
Class<?> rawType = typeInformation.getType();
|
||||
String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType);
|
||||
|
||||
Document document = rawType.getAnnotation(Document.class);
|
||||
|
||||
this.expression = detectExpression(document);
|
||||
this.context = new StandardEvaluationContext();
|
||||
|
||||
if (document != null) {
|
||||
|
||||
this.collection = StringUtils.hasText(document.collection()) ? document.collection() : fallback;
|
||||
this.language = StringUtils.hasText(document.language()) ? document.language() : "";
|
||||
if (rawType.isAnnotationPresent(Document.class)) {
|
||||
Document d = rawType.getAnnotation(Document.class);
|
||||
this.collection = StringUtils.hasText(d.collection()) ? d.collection() : fallback;
|
||||
} else {
|
||||
this.collection = fallback;
|
||||
this.language = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,34 +96,8 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getCollection()
|
||||
*/
|
||||
public String getCollection() {
|
||||
return expression == null ? collection : expression.getValue(context, String.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getLanguage()
|
||||
*/
|
||||
@Override
|
||||
public String getLanguage() {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getTextScoreProperty()
|
||||
*/
|
||||
@Override
|
||||
public MongoPersistentProperty getTextScoreProperty() {
|
||||
return getPersistentProperty(TextScore.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#hasTextScoreProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasTextScoreProperty() {
|
||||
return getTextScoreProperty() != null;
|
||||
Expression expression = parser.parseExpression(collection, ParserContext.TEMPLATE_EXPRESSION);
|
||||
return expression.getValue(context, String.class);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -144,22 +107,12 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
@Override
|
||||
public void verify() {
|
||||
|
||||
verifyFieldUniqueness();
|
||||
verifyFieldTypes();
|
||||
}
|
||||
|
||||
private void verifyFieldUniqueness() {
|
||||
|
||||
AssertFieldNameUniquenessHandler handler = new AssertFieldNameUniquenessHandler();
|
||||
|
||||
doWithProperties(handler);
|
||||
doWithAssociations(handler);
|
||||
}
|
||||
|
||||
private void verifyFieldTypes() {
|
||||
doWithProperties(new PropertyTypeAssertionHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order.
|
||||
*
|
||||
@@ -241,31 +194,6 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SpEL {@link Expression} frór the collection String expressed in the given {@link Document} annotation if
|
||||
* present or {@literal null} otherwise. Will also return {@literal null} it the collection {@link String} evaluates
|
||||
* to a {@link LiteralExpression} (indicating that no subsequent evaluation is necessary).
|
||||
*
|
||||
* @param document can be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
private static Expression detectExpression(Document document) {
|
||||
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String collection = document.collection();
|
||||
|
||||
if (!StringUtils.hasText(collection)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Expression expression = PARSER.parseExpression(document.collection(), ParserContext.TEMPLATE_EXPRESSION);
|
||||
|
||||
return expression instanceof LiteralExpression ? null : expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler to collect {@link MongoPersistentProperty} instances and check that each of them is mapped to a distinct
|
||||
* field name.
|
||||
@@ -298,46 +226,4 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
properties.put(fieldName, property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
private static class PropertyTypeAssertionHandler implements PropertyHandler<MongoPersistentProperty> {
|
||||
|
||||
@Override
|
||||
public void doWithPersistentProperty(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
potentiallyAssertTextScoreType(persistentProperty);
|
||||
potentiallyAssertLanguageType(persistentProperty);
|
||||
}
|
||||
|
||||
private void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isExplicitLanguageProperty()) {
|
||||
assertPropertyType(persistentProperty, String.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void potentiallyAssertTextScoreType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isTextScoreProperty()) {
|
||||
assertPropertyType(persistentProperty, Float.class, Double.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertPropertyType(MongoPersistentProperty persistentProperty, Class<?>... validMatches) {
|
||||
|
||||
for (Class<?> potentialMatch : validMatches) {
|
||||
if (ClassUtils.isAssignable(potentialMatch, persistentProperty.getActualType())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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-2013 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,9 +27,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -41,7 +39,6 @@ import com.mongodb.DBObject;
|
||||
* @author Oliver Gierke
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class BasicMongoPersistentProperty extends AnnotationBasedPersistentProperty<MongoPersistentProperty> implements
|
||||
MongoPersistentProperty {
|
||||
@@ -49,7 +46,6 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BasicMongoPersistentProperty.class);
|
||||
|
||||
private static final String ID_FIELD_NAME = "_id";
|
||||
private static final String LANGUAGE_FIELD_NAME = "language";
|
||||
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
|
||||
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
|
||||
|
||||
@@ -100,8 +96,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
}
|
||||
|
||||
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
|
||||
// but still we need to check if there happens to be an explicit name set
|
||||
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName()) && !hasExplicitFieldName();
|
||||
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,8 +130,10 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
}
|
||||
}
|
||||
|
||||
if (hasExplicitFieldName()) {
|
||||
return getAnnotatedFieldName();
|
||||
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class);
|
||||
|
||||
if (annotation != null && StringUtils.hasText(annotation.value())) {
|
||||
return annotation.value();
|
||||
}
|
||||
|
||||
String fieldName = fieldNamingStrategy.getFieldName(this);
|
||||
@@ -149,26 +146,6 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if {@link org.springframework.data.mongodb.core.mapping.Field} having non blank
|
||||
* {@link org.springframework.data.mongodb.core.mapping.Field#value()} present.
|
||||
* @since 1.7
|
||||
*/
|
||||
protected boolean hasExplicitFieldName() {
|
||||
return StringUtils.hasText(getAnnotatedFieldName());
|
||||
}
|
||||
|
||||
private String getAnnotatedFieldName() {
|
||||
|
||||
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class);
|
||||
|
||||
if (annotation != null && StringUtils.hasText(annotation.value())) {
|
||||
return annotation.value();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder()
|
||||
@@ -202,31 +179,4 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
public DBRef getDBRef() {
|
||||
return findAnnotation(DBRef.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isLanguageProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isLanguageProperty() {
|
||||
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isExplicitLanguageProperty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isExplicitLanguageProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isExplicitLanguageProperty() {
|
||||
return isAnnotationPresent(Language.class);
|
||||
};
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isTextScoreProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isTextScoreProperty() {
|
||||
return isAnnotationPresent(TextScore.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.data.mongodb.core.mapping;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
/**
|
||||
@@ -31,6 +30,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 +86,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
/**
|
||||
* {@link FieldNamingStrategy} that abbreviates field names by using the very first letter of the camel case parts of
|
||||
* the {@link MongoPersistentProperty}'s name.
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class CamelCaseAbbreviatingFieldNamingStrategy extends CamelCaseSplittingFieldNamingStrategy {
|
||||
|
||||
public CamelCaseAbbreviatingFieldNamingStrategy() {
|
||||
super("");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.CamelCaseSplittingFieldNamingStrategy#preparePart(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected String preparePart(String part) {
|
||||
return part.substring(0, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.util.ParsingUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configurable {@link FieldNamingStrategy} that splits up camel-case property names and reconcatenates them using a
|
||||
* configured delimiter. Individual parts of the name can be manipulated using {@link #preparePart(String)}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.5
|
||||
*/
|
||||
public class CamelCaseSplittingFieldNamingStrategy implements FieldNamingStrategy {
|
||||
|
||||
private final String delimiter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CamelCaseSplittingFieldNamingStrategy}.
|
||||
*
|
||||
* @param delimiter must not be {@literal null}.
|
||||
*/
|
||||
public CamelCaseSplittingFieldNamingStrategy(String delimiter) {
|
||||
|
||||
Assert.notNull(delimiter, "Delimiter must not be null!");
|
||||
this.delimiter = delimiter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.FieldNamingStrategy#getFieldName(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public String getFieldName(MongoPersistentProperty property) {
|
||||
|
||||
List<String> parts = ParsingUtils.splitCamelCaseToLower(property.getName());
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
for (String part : parts) {
|
||||
|
||||
String candidate = preparePart(part);
|
||||
|
||||
if (StringUtils.hasText(candidate)) {
|
||||
result.add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(result, delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to prepare the uncapitalized part obtained from the split up of the camel case source. Default
|
||||
* implementation returns the part as is.
|
||||
*
|
||||
* @param part
|
||||
* @return
|
||||
*/
|
||||
protected String preparePart(String part) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2014 by the original author(s).
|
||||
* Copyright (c) 2011 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.
|
||||
@@ -29,7 +29,6 @@ import org.springframework.data.annotation.Persistent;
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
* @author Oliver Gierke ogierke@vmware.com
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Persistent
|
||||
@Inherited
|
||||
@@ -38,13 +37,4 @@ import org.springframework.data.annotation.Persistent;
|
||||
public @interface Document {
|
||||
|
||||
String collection() default "";
|
||||
|
||||
/**
|
||||
* Defines the default language to be used with this document.
|
||||
*
|
||||
* @since 1.6
|
||||
* @return
|
||||
*/
|
||||
String language() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
/**
|
||||
* SPI interface to determine how to name document fields in cases the field name is not manually defined.
|
||||
*
|
||||
* @see DocumentField
|
||||
* @see PropertyNameFieldNamingStrategy
|
||||
* @see CamelCaseAbbreviatingFieldNamingStrategy
|
||||
* @see SnakeCaseFieldNamingStrategy
|
||||
* @since 1.3
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface FieldNamingStrategy {
|
||||
|
||||
/**
|
||||
* Returns the field name to be used for the given {@link MongoPersistentProperty}.
|
||||
*
|
||||
* @param property must not be {@literal null} or empty;
|
||||
* @return
|
||||
*/
|
||||
String getFieldName(MongoPersistentProperty property);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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,8 +24,6 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2012 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,6 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
* MongoDB specific {@link PersistentEntity} abstraction.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersistentProperty> {
|
||||
|
||||
@@ -31,30 +30,4 @@ public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersi
|
||||
* @return
|
||||
*/
|
||||
String getCollection();
|
||||
|
||||
/**
|
||||
* Returns the default language to be used for this entity.
|
||||
*
|
||||
* @since 1.6
|
||||
* @return
|
||||
*/
|
||||
String getLanguage();
|
||||
|
||||
/**
|
||||
* Returns the property holding text score value.
|
||||
*
|
||||
* @since 1.6
|
||||
* @see #hasTextScoreProperty()
|
||||
* @return {@literal null} if not present.
|
||||
*/
|
||||
MongoPersistentProperty getTextScoreProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the entity has a {@link TextScore} property.
|
||||
*
|
||||
* @since 1.6
|
||||
* @return true if property annotated with {@link TextScore} is present.
|
||||
*/
|
||||
boolean hasTextScoreProperty();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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,7 +26,6 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
* @author Oliver Gierke
|
||||
* @author Patryk Wasik
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface MongoPersistentProperty extends PersistentProperty<MongoPersistentProperty> {
|
||||
|
||||
@@ -45,7 +44,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
|
||||
@@ -60,32 +59,6 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
|
||||
*/
|
||||
boolean isExplicitIdProperty();
|
||||
|
||||
/**
|
||||
* Returns true whether the property indicates the documents language either by having a {@link #getFieldName()} equal
|
||||
* to {@literal language} or being annotated with {@link Language}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean isLanguageProperty();
|
||||
|
||||
/**
|
||||
* Returns true when property being annotated with {@link Language}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6.1
|
||||
*/
|
||||
boolean isExplicitLanguageProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property holds the documents score calculated by text search. <br/>
|
||||
* It's marked with {@link TextScore}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean isTextScoreProperty();
|
||||
|
||||
/**
|
||||
* Returns the {@link DBRef} if the property is a reference.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
/**
|
||||
* {@link FieldNamingStrategy} simply using the {@link MongoPersistentProperty}'s name.
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public enum PropertyNameFieldNamingStrategy implements FieldNamingStrategy {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.FieldNamingStrategy#getFieldName(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||
*/
|
||||
public String getFieldName(MongoPersistentProperty property) {
|
||||
return property.getName();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2013-2014 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,21 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mark property as language field.
|
||||
* {@link FieldNamingStrategy} that translates typical camel case Java property names to lower case JSON element names,
|
||||
* separated by underscores.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
* @since 1.5
|
||||
* @author Ryan Tenney
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Language {
|
||||
public class SnakeCaseFieldNamingStrategy extends CamelCaseSplittingFieldNamingStrategy {
|
||||
|
||||
/**
|
||||
* Creates a new {@link SnakeCaseFieldNamingStrategy}.
|
||||
*/
|
||||
public SnakeCaseFieldNamingStrategy() {
|
||||
super("_");
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
|
||||
/**
|
||||
* {@link TextScore} marks the property to be considered as the on server calculated {@literal textScore} when doing
|
||||
* full text search. <br />
|
||||
* <b>NOTE</b> Property will not be written when saving entity.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@ReadOnlyProperty
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface TextScore {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 - 2014 the original author or authors.
|
||||
* Copyright 2011 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,8 +26,7 @@ import com.mongodb.DBObject;
|
||||
* Collects the results of executing a group operation.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Christoph Strobl
|
||||
* @param <T> The class in which the results are mapped onto, accessible via an {@link Iterator}.
|
||||
* @param <T> The class in which the results are mapped onto, accessible via an interator.
|
||||
*/
|
||||
public class GroupByResults<T> implements Iterable<T> {
|
||||
|
||||
@@ -39,7 +38,6 @@ public class GroupByResults<T> implements Iterable<T> {
|
||||
private String serverUsed;
|
||||
|
||||
public GroupByResults(List<T> mappedResults, DBObject rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
Assert.notNull(rawResults);
|
||||
this.mappedResults = mappedResults;
|
||||
@@ -70,24 +68,21 @@ public class GroupByResults<T> implements Iterable<T> {
|
||||
}
|
||||
|
||||
private void parseCount() {
|
||||
|
||||
Object object = rawResults.get("count");
|
||||
if (object instanceof Number) {
|
||||
count = ((Number) object).doubleValue();
|
||||
if (object instanceof Double) {
|
||||
count = (Double) object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parseKeys() {
|
||||
|
||||
Object object = rawResults.get("keys");
|
||||
if (object instanceof Number) {
|
||||
keys = ((Number) object).intValue();
|
||||
if (object instanceof Integer) {
|
||||
keys = (Integer) object;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseServerUsed() {
|
||||
|
||||
// "serverUsed" : "127.0.0.1:27017"
|
||||
Object object = rawResults.get("serverUsed");
|
||||
if (object instanceof String) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2011 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.query;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.util.JSON;
|
||||
@@ -26,13 +24,11 @@ import com.mongodb.util.JSON;
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class BasicQuery extends Query {
|
||||
|
||||
private final DBObject queryObject;
|
||||
private DBObject fieldsObject;
|
||||
private final DBObject fieldsObject;
|
||||
private DBObject sortObject;
|
||||
|
||||
public BasicQuery(String query) {
|
||||
@@ -53,12 +49,8 @@ public class BasicQuery extends Query {
|
||||
this.fieldsObject = fieldsObject;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.Query#addCriteria(org.springframework.data.mongodb.core.query.CriteriaDefinition)
|
||||
*/
|
||||
@Override
|
||||
public Query addCriteria(CriteriaDefinition criteria) {
|
||||
public Query addCriteria(Criteria criteria) {
|
||||
this.queryObject.putAll(criteria.getCriteriaObject());
|
||||
return this;
|
||||
}
|
||||
@@ -92,50 +84,4 @@ public class BasicQuery extends Query {
|
||||
public void setSortObject(DBObject sortObject) {
|
||||
this.sortObject = sortObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
* @param fieldsObject
|
||||
*/
|
||||
protected void setFieldsObject(DBObject fieldsObject) {
|
||||
this.fieldsObject = fieldsObject;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.Query#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof BasicQuery)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BasicQuery that = (BasicQuery) o;
|
||||
|
||||
return querySettingsEquals(that) && //
|
||||
nullSafeEquals(fieldsObject, that.fieldsObject) && //
|
||||
nullSafeEquals(queryObject, that.queryObject) && //
|
||||
nullSafeEquals(sortObject, that.sortObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.Query#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + nullSafeHashCode(queryObject);
|
||||
result = 31 * result + nullSafeHashCode(fieldsObject);
|
||||
result = 31 * result + nullSafeHashCode(sortObject);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -390,6 +390,20 @@ public class Criteria implements CriteriaDefinition {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Criteria#withinSphere(Circle)
|
||||
* @param circle
|
||||
* @return
|
||||
* @deprecated As of 1.5, Use {@link #withinSphere(Circle)}. This method is scheduled to be removed in the next major
|
||||
* release.
|
||||
*/
|
||||
@Deprecated
|
||||
public Criteria withinSphere(org.springframework.data.mongodb.core.geo.Circle circle) {
|
||||
Assert.notNull(circle);
|
||||
criteria.put("$within", new GeoCommand(new Sphere(circle)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a geospatial criterion using a {@literal $within} operation.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2011 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,25 +17,8 @@ package org.springframework.data.mongodb.core.query;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface CriteriaDefinition {
|
||||
|
||||
/**
|
||||
* Get {@link DBObject} representation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DBObject getCriteriaObject();
|
||||
|
||||
/**
|
||||
* Get the identifying {@literal key}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -66,16 +66,17 @@ public class GeoCommand {
|
||||
* @param shape must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private String getCommand(Shape shape) {
|
||||
|
||||
Assert.notNull(shape, "Shape must not be null!");
|
||||
|
||||
if (shape instanceof Box) {
|
||||
return "$box";
|
||||
} else if (shape instanceof Circle) {
|
||||
return "$center";
|
||||
return org.springframework.data.mongodb.core.geo.Box.COMMAND;
|
||||
} else if (shape instanceof Circle || shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
|
||||
return org.springframework.data.mongodb.core.geo.Circle.COMMAND;
|
||||
} else if (shape instanceof Polygon) {
|
||||
return "$polygon";
|
||||
return org.springframework.data.mongodb.core.geo.Polygon.COMMAND;
|
||||
} else if (shape instanceof Sphere) {
|
||||
return org.springframework.data.mongodb.core.geo.Sphere.COMMAND;
|
||||
}
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.query;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Meta-data for {@link Query} instances.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
public class Meta {
|
||||
|
||||
private enum MetaKey {
|
||||
MAX_TIME_MS("$maxTimeMS"), MAX_SCAN("$maxScan"), COMMENT("$comment"), SNAPSHOT("$snapshot");
|
||||
|
||||
private String key;
|
||||
|
||||
private MetaKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, Object> values = new LinkedHashMap<String, Object>(2);
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
public Long getMaxTimeMsec() {
|
||||
return getValue(MetaKey.MAX_TIME_MS.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum time limit in milliseconds for processing operations.
|
||||
*
|
||||
* @param maxTimeMsec
|
||||
*/
|
||||
public void setMaxTimeMsec(long maxTimeMsec) {
|
||||
setMaxTime(maxTimeMsec, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum time limit for processing operations.
|
||||
*
|
||||
* @param timeout
|
||||
* @param timeUnit
|
||||
*/
|
||||
public void setMaxTime(long timeout, TimeUnit timeUnit) {
|
||||
setValue(MetaKey.MAX_TIME_MS.key, (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS).toMillis(timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
public Long getMaxScan() {
|
||||
return getValue(MetaKey.MAX_SCAN.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only scan the specified number of documents.
|
||||
*
|
||||
* @param maxScan
|
||||
*/
|
||||
public void setMaxScan(long maxScan) {
|
||||
setValue(MetaKey.MAX_SCAN.key, maxScan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to the query.
|
||||
*
|
||||
* @param comment
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
setValue(MetaKey.COMMENT.key, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
public String getComment() {
|
||||
return getValue(MetaKey.COMMENT.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Using snapshot prevents the cursor from returning a document more than once.
|
||||
*
|
||||
* @param useSnapshot
|
||||
*/
|
||||
public void setSnapshot(boolean useSnapshot) {
|
||||
setValue(MetaKey.SNAPSHOT.key, useSnapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal null} if not set.
|
||||
*/
|
||||
public boolean getSnapshot() {
|
||||
return getValue(MetaKey.SNAPSHOT.key, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean hasValues() {
|
||||
return !this.values.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Iterable} of set meta values.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Iterable<Entry<String, Object>> values() {
|
||||
return Collections.unmodifiableSet(this.values.entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or removes the value in case of {@literal null} or empty {@link String}.
|
||||
*
|
||||
* @param key must not be {@literal null} or empty.
|
||||
* @param value
|
||||
*/
|
||||
private void setValue(String key, Object value) {
|
||||
|
||||
Assert.hasText(key, "Meta key must not be 'null' or blank.");
|
||||
|
||||
if (value == null || (value instanceof String && !StringUtils.hasText((String) value))) {
|
||||
this.values.remove(key);
|
||||
}
|
||||
this.values.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getValue(String key) {
|
||||
return (T) this.values.get(key);
|
||||
}
|
||||
|
||||
private <T> T getValue(String key, T defaultValue) {
|
||||
|
||||
T value = getValue(key);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.values);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Meta)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Meta other = (Meta) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.values, other.values);
|
||||
}
|
||||
}
|
||||
@@ -343,6 +343,7 @@ public final class NearQuery {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public DBObject toDBObject() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -40,65 +39,56 @@ import com.mongodb.DBObject;
|
||||
* @author Thomas Risberg
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class Query {
|
||||
|
||||
private static final String RESTRICTED_TYPES_KEY = "_$RESTRICTED_TYPES";
|
||||
|
||||
private final Set<Class<?>> restrictedTypes = new HashSet<Class<?>>();
|
||||
private final Map<String, CriteriaDefinition> criteria = new LinkedHashMap<String, CriteriaDefinition>();
|
||||
private final Map<String, Criteria> criteria = new LinkedHashMap<String, Criteria>();
|
||||
private Field fieldSpec;
|
||||
private Sort sort;
|
||||
private int skip;
|
||||
private int limit;
|
||||
private String hint;
|
||||
|
||||
private Meta meta = new Meta();
|
||||
|
||||
/**
|
||||
* Static factory method to create a {@link Query} using the provided {@link CriteriaDefinition}.
|
||||
* Static factory method to create a {@link Query} using the provided {@link Criteria}.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
* @param criteria must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public static Query query(CriteriaDefinition criteriaDefinition) {
|
||||
return new Query(criteriaDefinition);
|
||||
public static Query query(Criteria criteria) {
|
||||
return new Query(criteria);
|
||||
}
|
||||
|
||||
public Query() {}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Query} using the given {@link CriteriaDefinition}.
|
||||
* Creates a new {@link Query} using the given {@link Criteria}.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
* @since 1.6
|
||||
* @param criteria must not be {@literal null}.
|
||||
*/
|
||||
public Query(CriteriaDefinition criteriaDefinition) {
|
||||
addCriteria(criteriaDefinition);
|
||||
public Query(Criteria criteria) {
|
||||
addCriteria(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link CriteriaDefinition} to the current {@link Query}.
|
||||
* Adds the given {@link Criteria} to the current {@link Query}.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
* @param criteria must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query addCriteria(CriteriaDefinition criteriaDefinition) {
|
||||
|
||||
CriteriaDefinition existing = this.criteria.get(criteriaDefinition.getKey());
|
||||
String key = criteriaDefinition.getKey();
|
||||
|
||||
public Query addCriteria(Criteria criteria) {
|
||||
CriteriaDefinition existing = this.criteria.get(criteria.getKey());
|
||||
String key = criteria.getKey();
|
||||
if (existing == null) {
|
||||
this.criteria.put(key, criteriaDefinition);
|
||||
this.criteria.put(key, criteria);
|
||||
} 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() + "'.");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -176,7 +166,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()));
|
||||
}
|
||||
}
|
||||
@@ -278,86 +268,8 @@ public class Query {
|
||||
return hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxTimeMsec
|
||||
* @return
|
||||
* @see Meta#setMaxTimeMsec(long)
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query maxTimeMsec(long maxTimeMsec) {
|
||||
|
||||
meta.setMaxTimeMsec(maxTimeMsec);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeout
|
||||
* @param timeUnit
|
||||
* @return
|
||||
* @see Meta#setMaxTime(long, TimeUnit)
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query maxTime(long timeout, TimeUnit timeUnit) {
|
||||
|
||||
meta.setMaxTime(timeout, timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxScan
|
||||
* @return
|
||||
* @see Meta#setMaxScan(long)
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query maxScan(long maxScan) {
|
||||
|
||||
meta.setMaxScan(maxScan);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param comment
|
||||
* @return
|
||||
* @see Meta#setComment(String)
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query comment(String comment) {
|
||||
|
||||
meta.setComment(comment);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see Meta#setSnapshot(boolean)
|
||||
* @since 1.6
|
||||
*/
|
||||
public Query useSnapshot() {
|
||||
|
||||
meta.setSnapshot(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return never {@literal null}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public Meta getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param meta must not be {@literal null}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public void setMeta(Meta meta) {
|
||||
|
||||
Assert.notNull(meta, "Query meta might be empty but must not be null.");
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
protected List<CriteriaDefinition> getCriteria() {
|
||||
return new ArrayList<CriteriaDefinition>(this.criteria.values());
|
||||
protected List<Criteria> getCriteria() {
|
||||
return new ArrayList<Criteria>(this.criteria.values());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -385,26 +297,16 @@ public class Query {
|
||||
return false;
|
||||
}
|
||||
|
||||
return querySettingsEquals((Query) obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the settings of the given {@link Query} are equal to this query.
|
||||
*
|
||||
* @param that
|
||||
* @return
|
||||
*/
|
||||
protected boolean querySettingsEquals(Query that) {
|
||||
Query that = (Query) obj;
|
||||
|
||||
boolean criteriaEqual = this.criteria.equals(that.criteria);
|
||||
boolean fieldsEqual = nullSafeEquals(this.fieldSpec, that.fieldSpec);
|
||||
boolean sortEqual = nullSafeEquals(this.sort, that.sort);
|
||||
boolean hintEqual = nullSafeEquals(this.hint, that.hint);
|
||||
boolean fieldsEqual = this.fieldSpec == null ? that.fieldSpec == null : this.fieldSpec.equals(that.fieldSpec);
|
||||
boolean sortEqual = this.sort == null ? that.sort == null : this.sort.equals(that.sort);
|
||||
boolean hintEqual = this.hint == null ? that.hint == null : this.hint.equals(that.hint);
|
||||
boolean skipEqual = this.skip == that.skip;
|
||||
boolean limitEqual = this.limit == that.limit;
|
||||
boolean metaEqual = nullSafeEquals(this.meta, that.meta);
|
||||
|
||||
return criteriaEqual && fieldsEqual && sortEqual && hintEqual && skipEqual && limitEqual && metaEqual;
|
||||
return criteriaEqual && fieldsEqual && sortEqual && hintEqual && skipEqual && limitEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -422,7 +324,6 @@ public class Query {
|
||||
result += 31 * nullSafeHashCode(hint);
|
||||
result += 31 * skip;
|
||||
result += 31 * limit;
|
||||
result += 31 * nullSafeHashCode(meta);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.query;
|
||||
|
||||
/**
|
||||
* A {@link Term} defines one or multiple words {@link Type#WORD} or phrases {@link Type#PHRASE} to be used in the
|
||||
* context of full text search.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
public class Term {
|
||||
|
||||
public enum Type {
|
||||
WORD, PHRASE;
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
private final String raw;
|
||||
private boolean negated;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Term} of {@link Type#WORD}.
|
||||
*
|
||||
* @param raw
|
||||
*/
|
||||
public Term(String raw) {
|
||||
this(raw, Type.WORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Term} of given {@link Type}.
|
||||
*
|
||||
* @param raw
|
||||
* @param type defaulted to {@link Type#WORD} if {@literal null}.
|
||||
*/
|
||||
public Term(String raw, Type type) {
|
||||
this.raw = raw;
|
||||
this.type = type == null ? Type.WORD : type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates the term.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Term negate() {
|
||||
this.negated = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return return true if term is negated.
|
||||
*/
|
||||
public boolean isNegated() {
|
||||
return negated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type of term. Never {@literal null}.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted representation of term.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFormatted() {
|
||||
|
||||
String formatted = Type.PHRASE.equals(type) ? quotePhrase(raw) : raw;
|
||||
return negated ? negateRaw(formatted) : formatted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFormatted();
|
||||
}
|
||||
|
||||
protected String quotePhrase(String raw) {
|
||||
return "\"" + raw + "\"";
|
||||
}
|
||||
|
||||
protected String negateRaw(String raw) {
|
||||
return "-" + raw;
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Implementation of {@link CriteriaDefinition} to be used for full text search.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
public class TextCriteria implements CriteriaDefinition {
|
||||
|
||||
private final List<Term> terms;
|
||||
private String language;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TextCriteria}.
|
||||
*
|
||||
* @see #forDefaultLanguage()
|
||||
* @see #forLanguage(String)
|
||||
*/
|
||||
public TextCriteria() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private TextCriteria(String language) {
|
||||
|
||||
this.language = language;
|
||||
this.terms = new ArrayList<Term>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link TextCriteria} for the default language.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TextCriteria forDefaultLanguage() {
|
||||
return new TextCriteria();
|
||||
}
|
||||
|
||||
/**
|
||||
* For a full list of supported languages see the mongdodb reference manual for <a
|
||||
* href="http://docs.mongodb.org/manual/reference/text-search-languages/">Text Search Languages</a>.
|
||||
*
|
||||
* @param language
|
||||
* @return
|
||||
*/
|
||||
public static TextCriteria forLanguage(String language) {
|
||||
|
||||
Assert.hasText(language, "Language must not be null or empty!");
|
||||
return new TextCriteria(language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link TextCriteria} to match any of the given words.
|
||||
*
|
||||
* @param words the words to match.
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria matchingAny(String... words) {
|
||||
|
||||
for (String word : words) {
|
||||
matching(word);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds given {@link Term} to criteria.
|
||||
*
|
||||
* @param term must not be {@literal null}.
|
||||
*/
|
||||
public TextCriteria matching(Term term) {
|
||||
|
||||
Assert.notNull(term, "Term to add must not be null.");
|
||||
|
||||
this.terms.add(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param term
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria matching(String term) {
|
||||
|
||||
if (StringUtils.hasText(term)) {
|
||||
matching(new Term(term));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param term
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria notMatching(String term) {
|
||||
|
||||
if (StringUtils.hasText(term)) {
|
||||
matching(new Term(term, Term.Type.WORD).negate());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param words
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria notMatchingAny(String... words) {
|
||||
|
||||
for (String word : words) {
|
||||
notMatching(word);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given value will treated as a single phrase.
|
||||
*
|
||||
* @param phrase
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria notMatchingPhrase(String phrase) {
|
||||
|
||||
if (StringUtils.hasText(phrase)) {
|
||||
matching(new Term(phrase, Term.Type.PHRASE).negate());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given value will treated as a single phrase.
|
||||
*
|
||||
* @param phrase
|
||||
* @return
|
||||
*/
|
||||
public TextCriteria matchingPhrase(String phrase) {
|
||||
|
||||
if (StringUtils.hasText(phrase)) {
|
||||
matching(new Term(phrase, Term.Type.PHRASE));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.CriteriaDefinition#getKey()
|
||||
*/
|
||||
@Override
|
||||
public String getKey() {
|
||||
return "$text";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.CriteriaDefinition#getCriteriaObject()
|
||||
*/
|
||||
@Override
|
||||
public DBObject getCriteriaObject() {
|
||||
|
||||
BasicDBObjectBuilder builder = new BasicDBObjectBuilder();
|
||||
|
||||
if (StringUtils.hasText(language)) {
|
||||
builder.add("$language", language);
|
||||
}
|
||||
|
||||
if (!terms.isEmpty()) {
|
||||
builder.add("$search", join(terms));
|
||||
}
|
||||
|
||||
return new BasicDBObject("$text", builder.get());
|
||||
}
|
||||
|
||||
private String join(Iterable<Term> terms) {
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
for (Term term : terms) {
|
||||
if (term != null) {
|
||||
result.add(term.getFormatted());
|
||||
}
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(result, " ");
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.query;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* {@link Query} implementation to be used to for performing full text searches.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
public class TextQuery extends Query {
|
||||
|
||||
private final String DEFAULT_SCORE_FIELD_FIELDNAME = "score";
|
||||
private final DBObject META_TEXT_SCORE = new BasicDBObject("$meta", "textScore");
|
||||
|
||||
private String scoreFieldName = DEFAULT_SCORE_FIELD_FIELDNAME;
|
||||
private boolean includeScore = false;
|
||||
private boolean sortByScore = false;
|
||||
|
||||
/**
|
||||
* Creates new {@link TextQuery} using the the given {@code wordsAndPhrases} with {@link TextCriteria}
|
||||
*
|
||||
* @param wordsAndPhrases
|
||||
* @see TextCriteria#matching(String)
|
||||
*/
|
||||
public TextQuery(String wordsAndPhrases) {
|
||||
super(TextCriteria.forDefaultLanguage().matching(wordsAndPhrases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link TextQuery} in {@code language}. <br />
|
||||
* For a full list of supported languages see the mongdodb reference manual for <a
|
||||
* href="http://docs.mongodb.org/manual/reference/text-search-languages/">Text Search Languages</a>.
|
||||
*
|
||||
* @param wordsAndPhrases
|
||||
* @param language
|
||||
* @see TextCriteria#forLanguage(String)
|
||||
* @see TextCriteria#matching(String)
|
||||
*/
|
||||
public TextQuery(String wordsAndPhrases, String language) {
|
||||
super(TextCriteria.forLanguage(language).matching(wordsAndPhrases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link TextQuery} using the {@code locale}s language.<br />
|
||||
* For a full list of supported languages see the mongdodb reference manual for <a
|
||||
* href="http://docs.mongodb.org/manual/reference/text-search-languages/">Text Search Languages</a>.
|
||||
*
|
||||
* @param wordsAndPhrases
|
||||
* @param locale
|
||||
*/
|
||||
public TextQuery(String wordsAndPhrases, Locale locale) {
|
||||
this(wordsAndPhrases, locale != null ? locale.getLanguage() : (String) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link TextQuery} for given {@link TextCriteria}.
|
||||
*
|
||||
* @param criteria.
|
||||
*/
|
||||
public TextQuery(TextCriteria criteria) {
|
||||
super(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link TextQuery} searching for given {@link TextCriteria}.
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
public static TextQuery queryText(TextCriteria criteria) {
|
||||
return new TextQuery(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sorting by text score. Will also add text score to returned fields.
|
||||
*
|
||||
* @see TextQuery#includeScore()
|
||||
* @return
|
||||
*/
|
||||
public TextQuery sortByScore() {
|
||||
|
||||
this.includeScore();
|
||||
this.sortByScore = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add field {@literal score} holding the documents textScore to the returned fields.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TextQuery includeScore() {
|
||||
|
||||
this.includeScore = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include text search document score in returned fields using the given fieldname.
|
||||
*
|
||||
* @param fieldname
|
||||
* @return
|
||||
*/
|
||||
public TextQuery includeScore(String fieldname) {
|
||||
|
||||
setScoreFieldName(fieldname);
|
||||
includeScore();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fieldname used for scoring.
|
||||
*
|
||||
* @param fieldName
|
||||
*/
|
||||
public void setScoreFieldName(String fieldName) {
|
||||
this.scoreFieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fieldname used for scoring
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getScoreFieldName() {
|
||||
return scoreFieldName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.Query#getFieldsObject()
|
||||
*/
|
||||
@Override
|
||||
public DBObject getFieldsObject() {
|
||||
|
||||
if (!this.includeScore) {
|
||||
return super.getFieldsObject();
|
||||
}
|
||||
|
||||
DBObject fields = super.getFieldsObject();
|
||||
|
||||
if (fields == null) {
|
||||
fields = new BasicDBObject();
|
||||
}
|
||||
|
||||
fields.put(getScoreFieldName(), META_TEXT_SCORE);
|
||||
return fields;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.query.Query#getSortObject()
|
||||
*/
|
||||
@Override
|
||||
public DBObject getSortObject() {
|
||||
|
||||
DBObject sort = new BasicDBObject();
|
||||
|
||||
if (this.sortByScore) {
|
||||
sort.put(getScoreFieldName(), META_TEXT_SCORE);
|
||||
}
|
||||
|
||||
if (super.getSortObject() != null) {
|
||||
sort.putAll(super.getSortObject());
|
||||
}
|
||||
|
||||
return sort;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -163,8 +163,7 @@ public class Update {
|
||||
|
||||
/**
|
||||
* Update using {@code $push} modifier. <br/>
|
||||
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values as well as using
|
||||
* {@code $position}.
|
||||
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/push/
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/each/
|
||||
@@ -190,12 +189,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 +253,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);
|
||||
addFieldOperation("$pullAll", key, Arrays.copyOf(values, values.length));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -281,61 +270,6 @@ public class Update {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update given key to current date using {@literal $currentDate} modifier.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/
|
||||
* @param key
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public Update currentDate(String key) {
|
||||
|
||||
addMultiFieldOperation("$currentDate", key, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update given key to current date using {@literal $currentDate : { $type : "timestamp" }} modifier.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/
|
||||
* @param key
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public Update currentTimestamp(String key) {
|
||||
|
||||
addMultiFieldOperation("$currentDate", key, new BasicDBObject("$type", "timestamp"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply the value of given key by the given number.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/operator/update/mul/
|
||||
* @param key must not be {@literal null}.
|
||||
* @param multiplier must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public Update multiply(String key, Number multiplier) {
|
||||
|
||||
Assert.notNull(multiplier, "Multiplier must not be 'null'.");
|
||||
addMultiFieldOperation("$mul", key, multiplier.doubleValue());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The operator supports bitwise {@code and}, bitwise {@code or}, and bitwise {@code xor} operations.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public BitwiseOperatorBuilder bitwise(String key) {
|
||||
return new BitwiseOperatorBuilder(this, key);
|
||||
}
|
||||
|
||||
public DBObject getUpdateObject() {
|
||||
|
||||
DBObject dbo = new BasicDBObject();
|
||||
@@ -523,13 +457,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -578,31 +506,6 @@ public class Update {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Modifier} implementation used to propagate {@code $position}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class PositionModifier implements Modifier {
|
||||
|
||||
private final int position;
|
||||
|
||||
public PositionModifier(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return "$position";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating {@code $push} modifiers
|
||||
*
|
||||
@@ -631,42 +534,6 @@ public class Update {
|
||||
return Update.this.push(key, this.modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces values to be added at the given {@literal position}.
|
||||
*
|
||||
* @param position needs to be greater than or equal to zero.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public PushOperatorBuilder atPosition(int position) {
|
||||
|
||||
if (position < 0) {
|
||||
throw new IllegalArgumentException("Position must be greater than or equal to zero.");
|
||||
}
|
||||
|
||||
this.modifiers.addModifier(new PositionModifier(position));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces values to be added at given {@literal position}.
|
||||
*
|
||||
* @param position can be {@literal null} which will be appended at the last position.
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
public PushOperatorBuilder atPosition(Position position) {
|
||||
|
||||
if (position == null || Position.LAST.equals(position)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.modifiers.addModifier(new PositionModifier(0));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates {@link #value(Object)} to {@code $push}
|
||||
*
|
||||
@@ -756,79 +623,4 @@ public class Update {
|
||||
return Update.this.addToSet(this.key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public static class BitwiseOperatorBuilder {
|
||||
|
||||
private final String key;
|
||||
private final Update reference;
|
||||
private static final String BIT_OPERATOR = "$bit";
|
||||
|
||||
private enum BitwiseOperator {
|
||||
AND, OR, XOR;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString().toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BitwiseOperatorBuilder}.
|
||||
*
|
||||
* @param reference must not be {@literal null}
|
||||
* @param key must not be {@literal null}
|
||||
*/
|
||||
protected BitwiseOperatorBuilder(Update reference, String key) {
|
||||
|
||||
Assert.notNull(reference, "Reference must not be null!");
|
||||
Assert.notNull(key, "Key must not be null!");
|
||||
|
||||
this.reference = reference;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates to the result of a bitwise and operation between the current value and the given one.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Update and(long value) {
|
||||
|
||||
addFieldOperation(BitwiseOperator.AND, value);
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates to the result of a bitwise or operation between the current value and the given one.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Update or(long value) {
|
||||
|
||||
addFieldOperation(BitwiseOperator.OR, value);
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates to the result of a bitwise xor operation between the current value and the given one.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Update xor(long value) {
|
||||
|
||||
addFieldOperation(BitwiseOperator.XOR, value);
|
||||
return reference;
|
||||
}
|
||||
|
||||
private void addFieldOperation(BitwiseOperator operator, Number value) {
|
||||
reference.addMultiFieldOperation(BIT_OPERATOR, key, new BasicDBObject(operator.toString(), value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.repository;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.QueryAnnotation;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
@QueryAnnotation
|
||||
public @interface Meta {
|
||||
|
||||
/**
|
||||
* Set the maximum time limit in milliseconds for processing operations.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
long maxExcecutionTime() default -1;
|
||||
|
||||
/**
|
||||
* Only scan the specified number of documents.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
long maxScanDocuments() default -1;
|
||||
|
||||
/**
|
||||
* Add a comment to the query.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String comment() default "";
|
||||
|
||||
/**
|
||||
* Using snapshot prevents the cursor from returning a document more than once.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean snapshot() default false;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
* Copyright 2010-2012 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,8 +26,6 @@ import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
* Mongo specific {@link org.springframework.data.repository.Repository} interface.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
|
||||
@@ -49,26 +47,4 @@ public interface MongoRepository<T, ID extends Serializable> extends PagingAndSo
|
||||
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
List<T> findAll(Sort sort);
|
||||
|
||||
/**
|
||||
* Inserts the given a given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use
|
||||
* the returned instance for further operations as the save operation might have changed the entity instance
|
||||
* completely. Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return the saved entity
|
||||
* @since 1.7
|
||||
*/
|
||||
<S extends T> S insert(S entity);
|
||||
|
||||
/**
|
||||
* Inserts the given entities. Assumes the given entities to have not been persisted yet and thus will optimize the
|
||||
* insert over a call to {@link #save(Iterable)}. Prefer using {@link #save(Iterable)} to avoid the usage of store
|
||||
* specific API.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
* @return the saved entities
|
||||
* @since 1.7
|
||||
*/
|
||||
<S extends T> List<S> insert(Iterable<S> entities);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,14 +25,12 @@ import javax.enterprise.inject.spi.BeanManager;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;
|
||||
import org.springframework.data.repository.cdi.CdiRepositoryBean;
|
||||
import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link CdiRepositoryBean} to create Mongo repository instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
|
||||
@@ -45,13 +43,11 @@ public class MongoRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
* @param qualifiers must not be {@literal null}.
|
||||
* @param repositoryType must not be {@literal null}.
|
||||
* @param beanManager must not be {@literal null}.
|
||||
* @param detector detector for the custom {@link org.springframework.data.repository.Repository} implementations
|
||||
* {@link CustomRepositoryImplementationDetector}, can be {@literal null}.
|
||||
*/
|
||||
public MongoRepositoryBean(Bean<MongoOperations> operations, Set<Annotation> qualifiers, Class<T> repositoryType,
|
||||
BeanManager beanManager, CustomRepositoryImplementationDetector detector) {
|
||||
BeanManager beanManager) {
|
||||
|
||||
super(qualifiers, repositoryType, beanManager, detector);
|
||||
super(qualifiers, repositoryType, beanManager);
|
||||
|
||||
Assert.notNull(operations);
|
||||
this.operations = operations;
|
||||
@@ -62,11 +58,11 @@ public class MongoRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
* @see org.springframework.data.repository.cdi.CdiRepositoryBean#create(javax.enterprise.context.spi.CreationalContext, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
|
||||
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
|
||||
|
||||
MongoOperations mongoOperations = getDependencyInstance(operations, MongoOperations.class);
|
||||
MongoRepositoryFactory factory = new MongoRepositoryFactory(mongoOperations);
|
||||
|
||||
return factory.getRepository(repositoryType, customImplementation);
|
||||
return factory.getRepository(repositoryType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
|
||||
* CDI extension to export Mongo repositories.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoRepositoryExtension extends CdiRepositoryExtensionSupport {
|
||||
|
||||
@@ -111,7 +110,6 @@ public class MongoRepositoryExtension extends CdiRepositoryExtensionSupport {
|
||||
}
|
||||
|
||||
// Construct and return the repository bean.
|
||||
return new MongoRepositoryBean<T>(mongoOperations, qualifiers, repositoryType, beanManager,
|
||||
getCustomImplementationDetector());
|
||||
return new MongoRepositoryBean<T>(mongoOperations, qualifiers, repositoryType, beanManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012 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,10 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -26,9 +22,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.config.BeanNames;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
|
||||
@@ -49,15 +43,6 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
|
||||
private boolean fallbackMappingContextCreated = false;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModuleName()
|
||||
*/
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
return "MongoDB";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix()
|
||||
@@ -75,24 +60,6 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
return MongoRepositoryFactoryBean.class.getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingAnnotations()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||
return Collections.<Class<? extends Annotation>> singleton(Document.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingTypes()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<?>> getIdentifyingTypes() {
|
||||
return Collections.<Class<?>> singleton(MongoRepository.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.RepositoryConfigurationSource)
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoPage;
|
||||
import org.springframework.data.geo.GeoResult;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Point;
|
||||
@@ -85,35 +84,39 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
MongoParameterAccessor accessor = new MongoParametersParameterAccessor(method, parameters);
|
||||
Query query = createQuery(new ConvertingParameterAccessor(operations.getConverter(), accessor));
|
||||
|
||||
applyQueryMetaAttributesWhenPresent(query);
|
||||
Object result = null;
|
||||
|
||||
if (isDeleteQuery()) {
|
||||
return new DeleteExecution().execute(query);
|
||||
result = new DeleteExecution().execute(query);
|
||||
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
|
||||
|
||||
MongoParameterAccessor countAccessor = new MongoParametersParameterAccessor(method, parameters);
|
||||
Query countQuery = createCountQuery(new ConvertingParameterAccessor(operations.getConverter(), countAccessor));
|
||||
|
||||
return new GeoNearExecution(accessor).execute(query, countQuery);
|
||||
result = new GeoNearExecution(accessor).execute(query, countQuery);
|
||||
} else if (method.isGeoNearQuery()) {
|
||||
return new GeoNearExecution(accessor).execute(query);
|
||||
result = new GeoNearExecution(accessor).execute(query);
|
||||
} else if (method.isSliceQuery()) {
|
||||
return new SlicedExecution(accessor.getPageable()).execute(query);
|
||||
result = new SlicedExecution(accessor.getPageable()).execute(query);
|
||||
} else if (method.isCollectionQuery()) {
|
||||
return new CollectionExecution(accessor.getPageable()).execute(query);
|
||||
result = new CollectionExecution(accessor.getPageable()).execute(query);
|
||||
} else if (method.isPageQuery()) {
|
||||
return new PagedExecution(accessor.getPageable()).execute(query);
|
||||
result = new PagedExecution(accessor.getPageable()).execute(query);
|
||||
} else {
|
||||
return new SingleEntityExecution(isCountQuery()).execute(query);
|
||||
result = new SingleEntityExecution(isCountQuery()).execute(query);
|
||||
}
|
||||
}
|
||||
|
||||
private Query applyQueryMetaAttributesWhenPresent(Query query) {
|
||||
|
||||
if (method.hasQueryMetaAttributes()) {
|
||||
query.setMeta(method.getQueryMetaAttributes());
|
||||
if (result == null) {
|
||||
return result;
|
||||
}
|
||||
return query;
|
||||
|
||||
Class<?> expectedReturnType = method.getReturnType().getType();
|
||||
|
||||
if (expectedReturnType.isAssignableFrom(result.getClass())) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return CONVERSION_SERVICE.convert(result, expectedReturnType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,12 +128,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
* @return
|
||||
*/
|
||||
protected Query createCountQuery(ConvertingParameterAccessor accessor) {
|
||||
|
||||
Query query = createQuery(accessor);
|
||||
|
||||
applyQueryMetaAttributesWhenPresent(query);
|
||||
|
||||
return query;
|
||||
return createQuery(accessor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +194,6 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
* {@link Execution} for {@link Slice} query methods.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
|
||||
@@ -218,11 +215,9 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
|
||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||
int pageSize = pageable.getPageSize();
|
||||
Pageable slicePageable = new PageRequest(pageable.getPageNumber(), pageSize + 1, pageable.getSort());
|
||||
|
||||
// Apply Pageable but tweak limit to peek into next page
|
||||
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
|
||||
|
||||
List result = operations.find(modifiedQuery, metadata.getJavaType(), metadata.getCollectionName());
|
||||
List result = operations.find(query.with(slicePageable), metadata.getJavaType(), metadata.getCollectionName());
|
||||
|
||||
boolean hasNext = result.size() > pageSize;
|
||||
|
||||
@@ -259,26 +254,10 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
Object execute(Query query) {
|
||||
|
||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||
|
||||
int overallLimit = query.getLimit();
|
||||
long count = operations.count(query, metadata.getCollectionName());
|
||||
count = overallLimit != 0 ? Math.min(count, query.getLimit()) : count;
|
||||
|
||||
boolean pageableOutOfScope = pageable.getOffset() > count;
|
||||
List<?> result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName());
|
||||
|
||||
if (pageableOutOfScope) {
|
||||
return new PageImpl<Object>(Collections.emptyList(), pageable, count);
|
||||
}
|
||||
|
||||
// Apply raw pagination
|
||||
query = query.with(pageable);
|
||||
|
||||
// Adjust limit if page would exceed the overall limit
|
||||
if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) {
|
||||
query.limit(overallLimit - pageable.getOffset());
|
||||
}
|
||||
|
||||
List<?> result = operations.find(query, metadata.getJavaType(), metadata.getCollectionName());
|
||||
return new PageImpl(result, pageable, count);
|
||||
}
|
||||
}
|
||||
@@ -314,6 +293,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
final class GeoNearExecution extends Execution {
|
||||
|
||||
private final MongoParameterAccessor accessor;
|
||||
@@ -345,11 +325,12 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||
long count = operations.count(countQuery, metadata.getCollectionName());
|
||||
|
||||
return new GeoPage<Object>(doExecuteQuery(query), accessor.getPageable(), count);
|
||||
return new org.springframework.data.mongodb.core.geo.GeoPage<Object>(doExecuteQuery(query),
|
||||
accessor.getPageable(), count);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private GeoResults<Object> doExecuteQuery(Query query) {
|
||||
private org.springframework.data.mongodb.core.geo.GeoResults<Object> doExecuteQuery(Query query) {
|
||||
|
||||
Point nearLocation = accessor.getGeoNearLocation();
|
||||
NearQuery nearQuery = NearQuery.near(nearLocation);
|
||||
@@ -369,7 +350,8 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
}
|
||||
|
||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||
return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
|
||||
return (org.springframework.data.mongodb.core.geo.GeoResults<Object>) operations.geoNear(nearQuery,
|
||||
metadata.getJavaType(), metadata.getCollectionName());
|
||||
}
|
||||
|
||||
private boolean isListOfGeoResult() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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,6 @@ import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.convert.MongoWriter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.query.TextCriteria;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,7 +38,6 @@ import com.mongodb.DBRef;
|
||||
* Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
|
||||
@@ -112,14 +110,6 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
|
||||
return delegate.getGeoNearLocation();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.MongoParameterAccessor#getFullText()
|
||||
*/
|
||||
public TextCriteria getFullText() {
|
||||
return delegate.getFullText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value with the underlying {@link MongoWriter}.
|
||||
*
|
||||
|
||||
@@ -17,14 +17,12 @@ package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.query.TextCriteria;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
|
||||
/**
|
||||
* Mongo-specific {@link ParameterAccessor} exposing a maximum distance parameter.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface MongoParameterAccessor extends ParameterAccessor {
|
||||
|
||||
@@ -42,12 +40,4 @@ public interface MongoParameterAccessor extends ParameterAccessor {
|
||||
* @return
|
||||
*/
|
||||
Point getGeoNearLocation();
|
||||
|
||||
/**
|
||||
* Returns the {@link TextCriteria} to be used for full text query.
|
||||
*
|
||||
* @return null if not set.
|
||||
* @since 1.6
|
||||
*/
|
||||
TextCriteria getFullText();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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,6 @@ import java.util.List;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.query.TextCriteria;
|
||||
import org.springframework.data.mongodb.repository.Near;
|
||||
import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
@@ -32,13 +31,10 @@ import org.springframework.data.repository.query.Parameters;
|
||||
* Custom extension of {@link Parameters} discovering additional
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoParameters extends Parameters<MongoParameters, MongoParameter> {
|
||||
|
||||
private final Integer distanceIndex;
|
||||
private final Integer fullTextIndex;
|
||||
|
||||
private Integer nearIndex;
|
||||
|
||||
/**
|
||||
@@ -52,7 +48,6 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
super(method);
|
||||
List<Class<?>> parameterTypes = Arrays.asList(method.getParameterTypes());
|
||||
this.distanceIndex = parameterTypes.indexOf(Distance.class);
|
||||
this.fullTextIndex = parameterTypes.indexOf(TextCriteria.class);
|
||||
|
||||
if (this.nearIndex == null && isGeoNearMethod) {
|
||||
this.nearIndex = getNearIndex(parameterTypes);
|
||||
@@ -61,19 +56,19 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
}
|
||||
}
|
||||
|
||||
private MongoParameters(List<MongoParameter> parameters, Integer distanceIndex, Integer nearIndex,
|
||||
Integer fullTextIndex) {
|
||||
private MongoParameters(List<MongoParameter> parameters, Integer distanceIndex, Integer nearIndex) {
|
||||
|
||||
super(parameters);
|
||||
|
||||
this.distanceIndex = distanceIndex;
|
||||
this.nearIndex = nearIndex;
|
||||
this.fullTextIndex = fullTextIndex;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "deprecation" })
|
||||
private final int getNearIndex(List<Class<?>> parameterTypes) {
|
||||
|
||||
for (Class<?> reference : Arrays.asList(Point.class, double[].class)) {
|
||||
for (Class<?> reference : Arrays.asList(Point.class, org.springframework.data.mongodb.core.geo.Point.class,
|
||||
double[].class)) {
|
||||
|
||||
int nearIndex = parameterTypes.indexOf(reference);
|
||||
|
||||
@@ -129,31 +124,13 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
return nearIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ths inde of the parameter to be used as a textquery param
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public int getFullTextParameterIndex() {
|
||||
return fullTextIndex != null ? fullTextIndex.intValue() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean hasFullTextParameter() {
|
||||
return this.fullTextIndex != null && this.fullTextIndex.intValue() >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.Parameters#createFrom(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected MongoParameters createFrom(List<MongoParameter> parameters) {
|
||||
return new MongoParameters(parameters, this.distanceIndex, this.nearIndex, this.fullTextIndex);
|
||||
return new MongoParameters(parameters, this.distanceIndex, this.nearIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,8 +162,7 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
*/
|
||||
@Override
|
||||
public boolean isSpecialParameter() {
|
||||
return super.isSpecialParameter() || Distance.class.isAssignableFrom(getType()) || isNearParameter()
|
||||
|| TextCriteria.class.isAssignableFrom(getType());
|
||||
return super.isSpecialParameter() || Distance.class.isAssignableFrom(getType()) || isNearParameter();
|
||||
}
|
||||
|
||||
private boolean isNearParameter() {
|
||||
@@ -205,7 +181,5 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
private boolean hasNearAnnotation() {
|
||||
return parameter.getParameterAnnotation(Near.class) != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,17 +17,12 @@ package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.query.Term;
|
||||
import org.springframework.data.mongodb.core.query.TextCriteria;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Mongo-specific {@link ParametersParameterAccessor} to allow access to the {@link Distance} parameter.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoParametersParameterAccessor extends ParametersParameterAccessor implements MongoParameterAccessor {
|
||||
|
||||
@@ -82,35 +77,4 @@ public class MongoParametersParameterAccessor extends ParametersParameterAccesso
|
||||
|
||||
return (Point) value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.MongoParameterAccessor#getFullText()
|
||||
*/
|
||||
@Override
|
||||
public TextCriteria getFullText() {
|
||||
int index = method.getParameters().getFullTextParameterIndex();
|
||||
return index >= 0 ? potentiallyConvertFullText(getValue(index)) : null;
|
||||
}
|
||||
|
||||
protected TextCriteria potentiallyConvertFullText(Object fullText) {
|
||||
|
||||
Assert.notNull(fullText, "Fulltext parameter must not be 'null'.");
|
||||
|
||||
if (fullText instanceof String) {
|
||||
return TextCriteria.forDefaultLanguage().matching((String) fullText);
|
||||
}
|
||||
|
||||
if (fullText instanceof Term) {
|
||||
return TextCriteria.forDefaultLanguage().matching((Term) fullText);
|
||||
}
|
||||
|
||||
if (fullText instanceof TextCriteria) {
|
||||
return ((TextCriteria) fullText);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Expected full text parameter to be one of String, Term or TextCriteria but found %s.",
|
||||
ClassUtils.getShortName(fullText.getClass())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,16 @@ import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
@@ -40,6 +43,7 @@ import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
|
||||
import org.springframework.data.repository.query.parser.Part.Type;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Custom query creator to create Mongo criterias.
|
||||
@@ -51,6 +55,7 @@ import org.springframework.util.Assert;
|
||||
class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MongoQueryCreator.class);
|
||||
private static final Pattern PUNCTATION_PATTERN = Pattern.compile("\\p{Punct}");
|
||||
private final MongoParameterAccessor accessor;
|
||||
private final boolean isGeoNearQuery;
|
||||
|
||||
@@ -103,7 +108,9 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
MongoPersistentProperty property = path.getLeafProperty();
|
||||
Criteria criteria = from(part, property, where(path.toDotPath()), (PotentiallyConvertingIterator) iterator);
|
||||
Criteria criteria = from(part, property,
|
||||
where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
|
||||
(PotentiallyConvertingIterator) iterator);
|
||||
|
||||
return criteria;
|
||||
}
|
||||
@@ -122,7 +129,9 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
MongoPersistentProperty property = path.getLeafProperty();
|
||||
|
||||
return from(part, property, base.and(path.toDotPath()), (PotentiallyConvertingIterator) iterator);
|
||||
return from(part, property,
|
||||
base.and(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
|
||||
(PotentiallyConvertingIterator) iterator);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -143,7 +152,11 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
@Override
|
||||
protected Query complete(Criteria criteria, Sort sort) {
|
||||
|
||||
Query query = (criteria == null ? new Query() : new Query(criteria)).with(sort);
|
||||
if (criteria == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Query query = new Query(criteria).with(sort);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Created query " + query);
|
||||
@@ -192,8 +205,6 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
case ENDING_WITH:
|
||||
case CONTAINING:
|
||||
return createContainingCriteria(part, property, criteria, parameters);
|
||||
case NOT_CONTAINING:
|
||||
return createContainingCriteria(part, property, criteria, parameters).not();
|
||||
case REGEX:
|
||||
return criteria.regex(parameters.next().toString());
|
||||
case EXISTS:
|
||||
@@ -211,7 +222,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
if (distance == null) {
|
||||
return criteria.near(point);
|
||||
} else {
|
||||
if (distance.getMetric() != null) {
|
||||
if (!Metrics.NEUTRAL.equals(distance.getMetric())) {
|
||||
criteria.nearSphere(point);
|
||||
} else {
|
||||
criteria.near(point);
|
||||
@@ -264,19 +275,23 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProperty property, Criteria criteria,
|
||||
PotentiallyConvertingIterator parameters, boolean shouldNegateExpression) {
|
||||
|
||||
PropertyPath path = part.getProperty().getLeafProperty();
|
||||
|
||||
switch (part.shouldIgnoreCase()) {
|
||||
|
||||
case ALWAYS:
|
||||
if (part.getProperty().getType() != String.class) {
|
||||
throw new IllegalArgumentException(String.format("part %s must be of type String but was %s",
|
||||
part.getProperty(), part.getType()));
|
||||
if (path.getType() != String.class) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Part %s must be of type String but was %s", path, path.getType()));
|
||||
}
|
||||
// fall-through
|
||||
|
||||
case WHEN_POSSIBLE:
|
||||
|
||||
if (shouldNegateExpression) {
|
||||
criteria = criteria.not();
|
||||
}
|
||||
|
||||
return addAppropriateLikeRegexTo(criteria, part, parameters.nextConverted(property).toString());
|
||||
|
||||
case NEVER:
|
||||
@@ -353,8 +368,8 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
return (T) parameter;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Expected parameter type of %s but got %s!", type,
|
||||
parameter.getClass()));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Expected parameter type of %s but got %s!", type, parameter.getClass()));
|
||||
}
|
||||
|
||||
private Object[] nextAsArray(PotentiallyConvertingIterator iterator, MongoPersistentProperty property) {
|
||||
@@ -372,24 +387,57 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
private String toLikeRegex(String source, Part part) {
|
||||
|
||||
Type type = part.getType();
|
||||
String regex = prepareAndEscapeStringBeforeApplyingLikeRegex(source, part);
|
||||
|
||||
switch (type) {
|
||||
case STARTING_WITH:
|
||||
source = "^" + source;
|
||||
regex = "^" + regex;
|
||||
break;
|
||||
case ENDING_WITH:
|
||||
source = source + "$";
|
||||
regex = regex + "$";
|
||||
break;
|
||||
case CONTAINING:
|
||||
case NOT_CONTAINING:
|
||||
source = "*" + source + "*";
|
||||
regex = ".*" + regex + ".*";
|
||||
break;
|
||||
case SIMPLE_PROPERTY:
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
source = "^" + source + "$";
|
||||
regex = "^" + regex + "$";
|
||||
default:
|
||||
}
|
||||
|
||||
return source.replaceAll("\\*", ".*");
|
||||
return regex;
|
||||
}
|
||||
|
||||
private String prepareAndEscapeStringBeforeApplyingLikeRegex(String source, Part qpart) {
|
||||
|
||||
if (!ObjectUtils.nullSafeEquals(Type.LIKE, qpart.getType())) {
|
||||
return PUNCTATION_PATTERN.matcher(source).find() ? Pattern.quote(source) : source;
|
||||
}
|
||||
|
||||
if (source.equals("*")) {
|
||||
return ".*";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
boolean leadingWildcard = source.startsWith("*");
|
||||
boolean trailingWildcard = source.endsWith("*");
|
||||
|
||||
String valueToUse = source.substring(leadingWildcard ? 1 : 0,
|
||||
trailingWildcard ? source.length() - 1 : source.length());
|
||||
|
||||
if (PUNCTATION_PATTERN.matcher(valueToUse).find()) {
|
||||
valueToUse = Pattern.quote(valueToUse);
|
||||
}
|
||||
|
||||
if (leadingWildcard) {
|
||||
sb.append(".*");
|
||||
}
|
||||
sb.append(valueToUse);
|
||||
if (trailingWildcard) {
|
||||
sb.append(".*");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2013 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,6 @@ import org.springframework.data.geo.GeoResults;
|
||||
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.repository.Meta;
|
||||
import org.springframework.data.mongodb.repository.Query;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
@@ -40,7 +39,6 @@ import org.springframework.util.StringUtils;
|
||||
* Mongo specific implementation of {@link QueryMethod}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoQueryMethod extends QueryMethod {
|
||||
|
||||
@@ -144,7 +142,7 @@ public class MongoQueryMethod extends QueryMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the query is a geo near query.
|
||||
* Returns whether te query is a geo near query.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@@ -182,55 +180,4 @@ public class MongoQueryMethod extends QueryMethod {
|
||||
TypeInformation<?> getReturnType() {
|
||||
return ClassTypeInformation.fromReturnTypeOf(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return return true if {@link Meta} annotation is available.
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean hasQueryMetaAttributes() {
|
||||
return getMetaAnnotation() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Meta} annotation that is applied to the method or {@code null} if not available.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
Meta getMetaAnnotation() {
|
||||
return method.getAnnotation(Meta.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link org.springframework.data.mongodb.core.query.Meta} attributes to be applied.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public org.springframework.data.mongodb.core.query.Meta getQueryMetaAttributes() {
|
||||
|
||||
Meta meta = getMetaAnnotation();
|
||||
if (meta == null) {
|
||||
return new org.springframework.data.mongodb.core.query.Meta();
|
||||
}
|
||||
|
||||
org.springframework.data.mongodb.core.query.Meta metaAttributes = new org.springframework.data.mongodb.core.query.Meta();
|
||||
if (meta.maxExcecutionTime() > 0) {
|
||||
metaAttributes.setMaxTimeMsec(meta.maxExcecutionTime());
|
||||
}
|
||||
|
||||
if (meta.maxScanDocuments() > 0) {
|
||||
metaAttributes.setMaxScan(meta.maxScanDocuments());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(meta.comment())) {
|
||||
metaAttributes.setComment(meta.comment());
|
||||
}
|
||||
|
||||
if (meta.snapshot()) {
|
||||
metaAttributes.setSnapshot(meta.snapshot());
|
||||
}
|
||||
|
||||
return metaAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user