Compare commits
15 Commits
1.7.0.RC1
...
1.7.0.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f16b30631 | ||
|
|
8ebcbe3c5c | ||
|
|
363bed5c37 | ||
|
|
1547a646dd | ||
|
|
1408d51065 | ||
|
|
f5c319f18f | ||
|
|
a3c29054d0 | ||
|
|
01533ca34c | ||
|
|
a1f6dc6db4 | ||
|
|
37d53d936d | ||
|
|
bc0a2df653 | ||
|
|
7e50fd8273 | ||
|
|
ba560ffbad | ||
|
|
50ca32c8b9 | ||
|
|
bdfe3af505 |
12
pom.xml
12
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.RC1</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.6.0.RC1</version>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>1.10.0.RC1</springdata.commons>
|
||||
<springdata.commons>1.10.0.RELEASE</springdata.commons>
|
||||
<mongo>2.13.0</mongo>
|
||||
<mongo.osgi>2.13.0</mongo.osgi>
|
||||
</properties>
|
||||
@@ -157,15 +157,15 @@
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-milestone</id>
|
||||
<url>http://repo.spring.io/libs-milestone</url>
|
||||
<id>spring-libs-release</id>
|
||||
<url>https://repo.spring.io/libs-release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>http://repo.spring.io/plugins-release</url>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.RC1</version>
|
||||
<version>1.7.0.RELEASE</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.RC1</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.RC1</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.RC1</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.7.0.RC1</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -145,6 +145,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jul-to-slf4j</artifactId>
|
||||
@@ -158,6 +165,13 @@
|
||||
<version>${equalsverifier}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonModule;
|
||||
import org.springframework.data.web.config.SpringDataWebConfigurationMixin;
|
||||
|
||||
/**
|
||||
* Configuration class to expose {@link GeoJsonModule} as a Spring bean.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SpringDataWebConfigurationMixin
|
||||
public class GeoJsonConfiguration {
|
||||
|
||||
@Bean
|
||||
public GeoJsonModule geoJsonModule() {
|
||||
return new GeoJsonModule();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* An {@link AggregationExpression} can be used with field expressions in aggregation pipeline stages like
|
||||
* {@code project} and {@code group}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface AggregationExpression {
|
||||
|
||||
/**
|
||||
* Turns the {@link AggregationExpression} into a {@link DBObject} within the given
|
||||
* {@link AggregationOperationContext}.
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
DBObject toDbObject(AggregationOperationContext context);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* An enum of supported {@link AggregationExpression}s in aggregation pipeline stages.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
*/
|
||||
public enum AggregationFunctionExpressions {
|
||||
|
||||
SIZE;
|
||||
|
||||
/**
|
||||
* Returns an {@link AggregationExpression} build from the current {@link Enum} name and the given parameters.
|
||||
*
|
||||
* @param parameters must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public AggregationExpression of(Object... parameters) {
|
||||
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
return new FunctionExpression(name().toLowerCase(), parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link AggregationExpression} representing a function call.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
*/
|
||||
static class FunctionExpression implements AggregationExpression {
|
||||
|
||||
private final String name;
|
||||
private final Object[] values;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionExpression} for the given name and values.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @param values must not be {@literal null}.
|
||||
*/
|
||||
public FunctionExpression(String name, Object[] values) {
|
||||
|
||||
Assert.hasText(name, "Name must not be null!");
|
||||
Assert.notNull(values, "Values must not be null!");
|
||||
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.Expression#toDbObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public DBObject toDbObject(AggregationOperationContext context) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>(values.length);
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
args.add(unpack(values[i], context));
|
||||
}
|
||||
|
||||
return new BasicDBObject("$" + name, args);
|
||||
}
|
||||
|
||||
private static Object unpack(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDbObject(context);
|
||||
}
|
||||
|
||||
if (value instanceof Field) {
|
||||
return context.getReference((Field) value).toString();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.LAST, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $last}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder last(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.LAST, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given field-reference.
|
||||
*
|
||||
@@ -203,6 +213,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.FIRST, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for a {@code $first}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder first(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.FIRST, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given field-reference.
|
||||
*
|
||||
@@ -213,6 +233,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.AVG, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $avg}-expression for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder avg(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.AVG, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $push}-expression for the given field-reference.
|
||||
*
|
||||
@@ -247,6 +277,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.MIN, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $min}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder min(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.MIN, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given field-reference.
|
||||
*
|
||||
@@ -257,6 +297,16 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.MAX, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $max}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
public GroupOperationBuilder max(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.MAX, null, expr);
|
||||
}
|
||||
|
||||
private GroupOperationBuilder newBuilder(Keyword keyword, String reference, Object value) {
|
||||
return new GroupOperationBuilder(this, new Operation(keyword, null, reference, value));
|
||||
}
|
||||
@@ -369,6 +419,11 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
public Object getValue(AggregationOperationContext context) {
|
||||
|
||||
if (reference == null) {
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDbObject(context);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,10 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return new ExpressionProjectionOperationBuilder(expression, this, params);
|
||||
}
|
||||
|
||||
public ProjectionOperationBuilder and(AggregationExpression expression) {
|
||||
return new ProjectionOperationBuilder(expression, this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes the given fields from the projection.
|
||||
*
|
||||
@@ -420,9 +424,13 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
if (this.previousProjection != null) {
|
||||
return this.operation.andReplaceLastOneWith(this.previousProjection.withAlias(alias));
|
||||
} else {
|
||||
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
||||
}
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return this.operation.and(new ExpressionProjection(Fields.field(alias), (AggregationExpression) value));
|
||||
}
|
||||
|
||||
return this.operation.and(new FieldProjection(Fields.field(alias, name), null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -552,6 +560,10 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
return project("mod", Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
public ProjectionOperationBuilder size() {
|
||||
return project("size");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
@@ -940,4 +952,31 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
|
||||
*/
|
||||
public abstract DBObject toDBObject(AggregationOperationContext context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
static class ExpressionProjection extends Projection {
|
||||
|
||||
private final AggregationExpression expression;
|
||||
private final Field field;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionProjection}.
|
||||
*
|
||||
* @param field
|
||||
* @param expression
|
||||
*/
|
||||
public ExpressionProjection(Field field, AggregationExpression expression) {
|
||||
|
||||
super(field);
|
||||
this.field = field;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBObject toDBObject(AggregationOperationContext context) {
|
||||
return new BasicDBObject(field.getName(), expression.toDbObject(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* A Jackson {@link Module} to register custom {@link JsonSerializer} and {@link JsonDeserializer}s for GeoJSON types.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
public class GeoJsonModule extends SimpleModule {
|
||||
|
||||
private static final long serialVersionUID = -8723016728655643720L;
|
||||
|
||||
public GeoJsonModule() {
|
||||
|
||||
addDeserializer(GeoJsonPoint.class, new GeoJsonPointDeserializer());
|
||||
addDeserializer(GeoJsonMultiPoint.class, new GeoJsonMultiPointDeserializer());
|
||||
addDeserializer(GeoJsonLineString.class, new GeoJsonLineStringDeserializer());
|
||||
addDeserializer(GeoJsonMultiLineString.class, new GeoJsonMultiLineStringDeserializer());
|
||||
addDeserializer(GeoJsonPolygon.class, new GeoJsonPolygonDeserializer());
|
||||
addDeserializer(GeoJsonMultiPolygon.class, new GeoJsonMultiPolygonDeserializer());
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static abstract class GeoJsonDeserializer<T extends GeoJson<?>> extends JsonDeserializer<T> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
|
||||
*/
|
||||
@Override
|
||||
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
|
||||
JsonNode node = jp.readValueAsTree();
|
||||
JsonNode coordinates = node.get("coordinates");
|
||||
|
||||
if (coordinates != null && coordinates.isArray()) {
|
||||
return doDeserialize((ArrayNode) coordinates);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual deserialization given the {@literal coordinates} as {@link ArrayNode}.
|
||||
*
|
||||
* @param coordinates
|
||||
* @return
|
||||
*/
|
||||
protected abstract T doDeserialize(ArrayNode coordinates);
|
||||
|
||||
/**
|
||||
* Get the {@link GeoJsonPoint} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
|
||||
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal null} when given a {@code null} value.
|
||||
*/
|
||||
protected GeoJsonPoint toGeoJsonPoint(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GeoJsonPoint(node.get(0).asDouble(), node.get(1).asDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Point} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
|
||||
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal null} when given a {@code null} value.
|
||||
*/
|
||||
protected Point toPoint(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Point(node.get(0).asDouble(), node.get(1).asDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the points nested within given {@link ArrayNode}.
|
||||
*
|
||||
* @param node can be {@literal null}.
|
||||
* @return {@literal empty list} when given a {@code null} value.
|
||||
*/
|
||||
protected List<Point> toPoints(ArrayNode node) {
|
||||
|
||||
if (node == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Point> points = new ArrayList<Point>(node.size());
|
||||
|
||||
for (JsonNode coordinatePair : node) {
|
||||
if (coordinatePair.isArray()) {
|
||||
points.add(toPoint((ArrayNode) coordinatePair));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
protected GeoJsonLineString toLineString(ArrayNode node) {
|
||||
return new GeoJsonLineString(toPoints((ArrayNode) node));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Point}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* { "type": "Point", "coordinates": [10.0, 20.0] }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonPointDeserializer extends GeoJsonDeserializer<GeoJsonPoint> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonPoint doDeserialize(ArrayNode coordinates) {
|
||||
return toGeoJsonPoint(coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal LineString}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "LineString",
|
||||
* "coordinates": [
|
||||
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonLineStringDeserializer extends GeoJsonDeserializer<GeoJsonLineString> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonLineString doDeserialize(ArrayNode coordinates) {
|
||||
return new GeoJsonLineString(toPoints(coordinates));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPoint}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiPoint",
|
||||
* "coordinates": [
|
||||
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiPointDeserializer extends GeoJsonDeserializer<GeoJsonMultiPoint> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiPoint doDeserialize(ArrayNode coordinates) {
|
||||
return new GeoJsonMultiPoint(toPoints(coordinates));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiLineString}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiLineString",
|
||||
* "coordinates": [
|
||||
* [ [10.0, 20.0], [30.0, 40.0] ],
|
||||
* [ [50.0, 60.0] , [70.0, 80.0] ]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiLineStringDeserializer extends GeoJsonDeserializer<GeoJsonMultiLineString> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiLineString doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>(coordinates.size());
|
||||
|
||||
for (JsonNode lineString : coordinates) {
|
||||
if (lineString.isArray()) {
|
||||
lines.add(toLineString((ArrayNode) lineString));
|
||||
}
|
||||
}
|
||||
|
||||
return new GeoJsonMultiLineString(lines);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Polygon}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "Polygon",
|
||||
* "coordinates": [
|
||||
* [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonPolygonDeserializer extends GeoJsonDeserializer<GeoJsonPolygon> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonPolygon doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
for (JsonNode ring : coordinates) {
|
||||
|
||||
// currently we do not support holes in polygons.
|
||||
return new GeoJsonPolygon(toPoints((ArrayNode) ring));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPolygon}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {
|
||||
* "type": "MultiPolygon",
|
||||
* "coordinates": [
|
||||
* [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
|
||||
* [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
|
||||
* [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
|
||||
* ]
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class GeoJsonMultiPolygonDeserializer extends GeoJsonDeserializer<GeoJsonMultiPolygon> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
|
||||
*/
|
||||
@Override
|
||||
protected GeoJsonMultiPolygon doDeserialize(ArrayNode coordinates) {
|
||||
|
||||
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>(coordinates.size());
|
||||
|
||||
for (JsonNode polygon : coordinates) {
|
||||
for (JsonNode ring : (ArrayNode) polygon) {
|
||||
polygones.add(new GeoJsonPolygon(toPoints((ArrayNode) ring)));
|
||||
}
|
||||
}
|
||||
|
||||
return new GeoJsonMultiPolygon(polygones);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexInformation.add(indexDefinitionHolder);
|
||||
}
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -155,7 +155,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
indexInformation.addAll(resolveIndexForClass(persistentProperty.getActualType(), propertyDotPath,
|
||||
collection, guard));
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
appendTextIndexInformation("", indexDefinitionBuilder, root,
|
||||
new TextIndexIncludeOptions(IncludeStrategy.DEFAULT), new CycleGuard());
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.info(e.getMessage());
|
||||
}
|
||||
|
||||
TextIndexDefinition indexDefinition = indexDefinitionBuilder.build();
|
||||
@@ -256,9 +256,9 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
appendTextIndexInformation(propertyDotPath, indexDefinitionBuilder,
|
||||
mappingContext.getPersistentEntity(persistentProperty.getActualType()), optionsForNestedType, guard);
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
LOGGER.info(e.getMessage(), e);
|
||||
} catch (InvalidDataAccessApiUsageException e) {
|
||||
LOGGER.warn(
|
||||
LOGGER.info(
|
||||
String.format("Potentially invald index structure discovered. Breaking operation for %s.",
|
||||
entity.getName()), e);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,8 +97,8 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
|
||||
return result;
|
||||
|
||||
} catch (JSONParseException o_O) {
|
||||
throw new IllegalStateException(String.format("Invalid query or field specification in %s!", getQueryMethod(),
|
||||
o_O));
|
||||
throw new IllegalStateException(String.format("Invalid query or field specification in %s!", getQueryMethod()),
|
||||
o_O);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.GeoJsonConfiguration;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonModule;
|
||||
import org.springframework.data.web.config.EnableSpringDataWebSupport;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link GeoJsonConfiguration}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class GeoJsonConfigurationIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableSpringDataWebSupport
|
||||
static class Config {}
|
||||
|
||||
@Autowired GeoJsonModule geoJsonModule;
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void picksUpGeoJsonModuleConfigurationByDefault() {
|
||||
assertThat(geoJsonModule, is(notNullValue()));
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -17,8 +17,11 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.AggregationFunctionExpressions.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Fields.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mongodb.core.DBObjectTestUtils;
|
||||
|
||||
@@ -29,6 +32,7 @@ import com.mongodb.DBObject;
|
||||
* Unit tests for {@link GroupOperation}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class GroupOperationUnitTests {
|
||||
|
||||
@@ -183,6 +187,23 @@ public class GroupOperationUnitTests {
|
||||
assertThat(push, is((DBObject) new BasicDBObject("$addToSet", 42)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-979
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderSizeExpressionInGroup() {
|
||||
|
||||
GroupOperation groupOperation = Aggregation //
|
||||
.group("username") //
|
||||
.first(SIZE.of(field("tags"))) //
|
||||
.as("tags_count");
|
||||
|
||||
DBObject groupClause = extractDbObjectFromGroupOperation(groupOperation);
|
||||
DBObject tagsCount = DBObjectTestUtils.getAsDBObject(groupClause, "tags_count");
|
||||
|
||||
assertThat(tagsCount.get("$first"), is((Object) new BasicDBObject("$size", Arrays.asList("$tags"))));
|
||||
}
|
||||
|
||||
private DBObject extractDbObjectFromGroupOperation(GroupOperation groupOperation) {
|
||||
DBObject dbObject = groupOperation.toDBObject(Aggregation.DEFAULT_CONTEXT);
|
||||
DBObject groupClause = DBObjectTestUtils.getAsDBObject(dbObject, "$group");
|
||||
|
||||
@@ -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.
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.AggregationFunctionExpressions.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Fields.*;
|
||||
import static org.springframework.data.mongodb.util.DBObjectUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -334,6 +336,41 @@ public class ProjectionOperationUnitTests {
|
||||
"$date", 86400000))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-979
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderSizeExpressionInProjection() {
|
||||
|
||||
ProjectionOperation operation = Aggregation //
|
||||
.project() //
|
||||
.and("tags") //
|
||||
.size()//
|
||||
.as("tags_count");
|
||||
|
||||
DBObject dbObject = operation.toDBObject(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
DBObject projected = exctractOperation("$project", dbObject);
|
||||
assertThat(projected.get("tags_count"), is((Object) new BasicDBObject("$size", Arrays.asList("$tags"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-979
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderGenericSizeExpressionInProjection() {
|
||||
|
||||
ProjectionOperation operation = Aggregation //
|
||||
.project() //
|
||||
.and(SIZE.of(field("tags"))) //
|
||||
.as("tags_count");
|
||||
|
||||
DBObject dbObject = operation.toDBObject(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
DBObject projected = exctractOperation("$project", dbObject);
|
||||
assertThat(projected.get("tags_count"), is((Object) new BasicDBObject("$size", Arrays.asList("$tags"))));
|
||||
}
|
||||
|
||||
private static DBObject exctractOperation(String field, DBObject fromProjectClause) {
|
||||
return (DBObject) fromProjectClause.get(field);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.geo;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class GeoJsonModuleUnitTests {
|
||||
|
||||
ObjectMapper mapper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
mapper = new ObjectMapper();
|
||||
mapper.registerModule(new GeoJsonModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserializeJsonPointCorrectly() throws JsonParseException, JsonMappingException, IOException {
|
||||
|
||||
String json = "{ \"type\": \"Point\", \"coordinates\": [10.0, 20.0] }";
|
||||
|
||||
assertThat(mapper.readValue(json, GeoJsonPoint.class), is(new GeoJsonPoint(10D, 20D)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserializeGeoJsonLineStringCorrectly() throws JsonParseException, JsonMappingException,
|
||||
IOException {
|
||||
|
||||
String json = "{ \"type\": \"LineString\", \"coordinates\": [ [10.0, 20.0], [30.0, 40.0], [50.0, 60.0] ]}";
|
||||
|
||||
assertThat(mapper.readValue(json, GeoJsonLineString.class),
|
||||
is(new GeoJsonLineString(Arrays.asList(new Point(10, 20), new Point(30, 40), new Point(50, 60)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserializeGeoJsonMultiPointCorrectly() throws JsonParseException, JsonMappingException,
|
||||
IOException {
|
||||
|
||||
String json = "{ \"type\": \"MultiPoint\", \"coordinates\": [ [10.0, 20.0], [30.0, 40.0], [50.0, 60.0] ]}";
|
||||
|
||||
assertThat(mapper.readValue(json, GeoJsonLineString.class),
|
||||
is(new GeoJsonMultiPoint(Arrays.asList(new Point(10, 20), new Point(30, 40), new Point(50, 60)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldDeserializeGeoJsonMultiLineStringCorrectly() throws JsonParseException, JsonMappingException,
|
||||
IOException {
|
||||
|
||||
String json = "{ \"type\": \"MultiLineString\", \"coordinates\": [ [ [10.0, 20.0], [30.0, 40.0] ], [ [50.0, 60.0] , [70.0, 80.0] ] ]}";
|
||||
|
||||
assertThat(
|
||||
mapper.readValue(json, GeoJsonMultiLineString.class),
|
||||
is(new GeoJsonMultiLineString(Arrays.asList(new Point(10, 20), new Point(30, 40)), Arrays.asList(new Point(50,
|
||||
60), new Point(70, 80)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserializeGeoJsonPolygonCorrectly() throws JsonParseException, JsonMappingException, IOException {
|
||||
|
||||
String json = "{ \"type\": \"Polygon\", \"coordinates\": [ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] ]}";
|
||||
|
||||
assertThat(
|
||||
mapper.readValue(json, GeoJsonPolygon.class),
|
||||
is(new GeoJsonPolygon(Arrays.asList(new Point(100, 0), new Point(101, 0), new Point(101, 1), new Point(100, 1),
|
||||
new Point(100, 0)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1181
|
||||
*/
|
||||
@Test
|
||||
public void shouldDeserializeGeoJsonMultiPolygonCorrectly() throws JsonParseException, JsonMappingException,
|
||||
IOException {
|
||||
|
||||
String json = "{ \"type\": \"Polygon\", \"coordinates\": ["
|
||||
+ "[[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],"
|
||||
+ "[[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],"
|
||||
+ "[[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]"//
|
||||
+ "]}";
|
||||
|
||||
assertThat(
|
||||
mapper.readValue(json, GeoJsonMultiPolygon.class),
|
||||
is(new GeoJsonMultiPolygon(Arrays.asList(
|
||||
new GeoJsonPolygon(Arrays.asList(new Point(102, 2), new Point(103, 2), new Point(103, 3),
|
||||
new Point(102, 3), new Point(102, 2))),
|
||||
new GeoJsonPolygon(Arrays.asList(new Point(100, 0), new Point(101, 0), new Point(101, 1),
|
||||
new Point(100, 1), new Point(100, 0))),
|
||||
new GeoJsonPolygon(Arrays.asList(new Point(100.2, 0.2), new Point(100.8, 0.2), new Point(100.8, 0.8),
|
||||
new Point(100.2, 0.8), new Point(100.2, 0.2)))))));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -45,6 +45,7 @@ import org.springframework.data.mongodb.repository.Query;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.util.JSONParseException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PartTreeMongoQuery}.
|
||||
@@ -135,6 +136,18 @@ public class PartTreeMongoQueryUnitTests {
|
||||
assertThat(query, isTextQuery().searchingFor("search").where(new Criteria("firstname").is("text")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1180
|
||||
*/
|
||||
@Test
|
||||
public void propagatesRootExceptionForInvalidQuery() {
|
||||
|
||||
exception.expect(IllegalStateException.class);
|
||||
exception.expectCause(is(org.hamcrest.Matchers.<Throwable> instanceOf(JSONParseException.class)));
|
||||
|
||||
deriveQueryFromMethod("findByAge", new Object[] { 1 });
|
||||
}
|
||||
|
||||
private org.springframework.data.mongodb.core.query.Query deriveQueryFromMethod(String method, Object[] args) {
|
||||
|
||||
Class<?>[] types = new Class<?>[args.length];
|
||||
@@ -179,5 +192,8 @@ public class PartTreeMongoQueryUnitTests {
|
||||
Person findPersonByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
Person findPersonByFirstname(String firstname, TextCriteria fullText);
|
||||
|
||||
@Query(fields = "{ 'firstname }")
|
||||
Person findByAge(Integer age);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ Import-Package:
|
||||
Export-Template:
|
||||
org.springframework.data.mongodb.*;version="${project.version}"
|
||||
Import-Template:
|
||||
com.fasterxml.jackson.*;version="${jackson:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
com.google.common.base.*;version="[11.0.0,14.0.0)";resolution:=optional,
|
||||
com.mongodb.*;version="${mongo.osgi:[=.=.=,+1.0.0)}",
|
||||
com.mysema.query.*;version="[2.1.1, 3.0.0)";resolution:=optional,
|
||||
|
||||
@@ -4,9 +4,9 @@ Mark Pollack; Thomas Risberg; Oliver Gierke; Costin Leau; Jon Brisbin; Thomas Da
|
||||
:revdate: {localdate}
|
||||
:toc:
|
||||
:toc-placement!:
|
||||
:spring-data-commons-docs: https://raw.githubusercontent.com/spring-projects/spring-data-commons/master/src/main/asciidoc
|
||||
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
|
||||
|
||||
(C) 2008-2014 The original authors.
|
||||
(C) 2008-2015 The original authors.
|
||||
|
||||
NOTE: _Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically._
|
||||
|
||||
@@ -15,6 +15,7 @@ toc::[]
|
||||
include::preface.adoc[]
|
||||
|
||||
:leveloffset: +1
|
||||
include::new-features.adoc[]
|
||||
include::{spring-data-commons-docs}/repositories.adoc[]
|
||||
:leveloffset: -1
|
||||
|
||||
@@ -42,4 +43,5 @@ include::reference/mongo-3.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-namespace-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-populator-namespace-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-query-keywords-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-query-return-types-reference.adoc[]
|
||||
:leveloffset: -1
|
||||
|
||||
15
src/main/asciidoc/new-features.adoc
Normal file
15
src/main/asciidoc/new-features.adoc
Normal file
@@ -0,0 +1,15 @@
|
||||
[[new-features]]
|
||||
= New & Noteworthy
|
||||
|
||||
[[new-features.1-7-0]]
|
||||
== What's new in Spring Data MongoDB 1.7
|
||||
|
||||
* Assert compatibility with MongoDB 3.0 and MongoDB Java Driver 3-beta3 (see: <<mongo.mongo-3>>).
|
||||
* Support JSR-310 and ThreeTen back-port date/time types.
|
||||
* Allow `Stream` as query method return type (see: <<mongodb.repositories.queries>>).
|
||||
* Added http://geojson.org/[GeoJSON] support in both domain types and queries (see: <<mongo.geo-json>>).
|
||||
* `QueryDslPredicateExcecutor` now supports `findAll(OrderSpecifier<?>… orders)`.
|
||||
* Support calling JavaScript functions via <<mongo.server-side-scripts>>.
|
||||
* Improve support for `CONTAINS` keyword on collection like properties.
|
||||
* Support for `$bit`, `$mul` and `$position` operators to `Update`.
|
||||
|
||||
@@ -30,9 +30,9 @@ The jumping off ground for learning about MongoDB is http://www.mongodb.org/[www
|
||||
[[requirements]]
|
||||
== Requirements
|
||||
|
||||
Spring Data MongoDB 1.x binaries requires JDK level 6.0 and above, and http://spring.io/docs[Spring Framework] 3.2.x and above.
|
||||
Spring Data MongoDB 1.x binaries requires JDK level 6.0 and above, and http://spring.io/docs[Spring Framework] 4.0.x and above.
|
||||
|
||||
In terms of document stores, http://www.mongodb.org/[MongoDB] at least 2.4, preferably version 2.6.
|
||||
In terms of document stores, http://www.mongodb.org/[MongoDB] at least 2.6.
|
||||
|
||||
== Additional Help Resources
|
||||
|
||||
@@ -46,12 +46,12 @@ There are a few support options available:
|
||||
[[get-started:help:community]]
|
||||
==== Community Forum
|
||||
|
||||
Spring Data on Stackoverflow http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow ] is a tag for all Spring Data (not just Document) users to share information and help each other. Note that registration is needed *only* for posting.
|
||||
Spring Data on Stackoverflow http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow] is a tag for all Spring Data (not just Document) users to share information and help each other. Note that registration is needed *only* for posting.
|
||||
|
||||
[[get-started:help:professional]]
|
||||
==== Professional Support
|
||||
|
||||
Professional, from-the-source support, with guaranteed response time, is available from http://gopivotal.com/[Pivotal Sofware, Inc.], the company behind Spring Data and Spring.
|
||||
Professional, from-the-source support, with guaranteed response time, is available from http://pivotal.io/[Pivotal Sofware, Inc.], the company behind Spring Data and Spring.
|
||||
|
||||
[[get-started:up-to-date]]
|
||||
=== Following Development
|
||||
|
||||
@@ -134,16 +134,22 @@ Most of the data access operations you usually trigger on a repository result a
|
||||
----
|
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, String> {
|
||||
|
||||
List<Person> findByLastname(String lastname);
|
||||
List<Person> findByLastname(String lastname); <1>
|
||||
|
||||
Page<Person> findByFirstname(String firstname, Pageable pageable);
|
||||
Page<Person> findByFirstname(String firstname, Pageable pageable); <2>
|
||||
|
||||
Person findByShippingAddresses(Address address);
|
||||
Person findByShippingAddresses(Address address); <3>
|
||||
|
||||
Stream<Person> findAllBy(); <4>
|
||||
}
|
||||
----
|
||||
<1> The method shows a query for all people with the given lastname. The query will be derived parsing the method name for constraints which can be concatenated with `And` and `Or`. Thus the method name will result in a query expression of `{"lastname" : lastname}`.
|
||||
<2> Applies pagination to a query. Just equip your method signature with a `Pageable` parameter and let the method return a `Page` instance and we will automatically page the query accordingly.
|
||||
<3> Shows that you can query based on properties which are not a primitive type.
|
||||
<4> Uses a Java 8 `Stream` which reads and converts individual elements while iterating the stream.
|
||||
====
|
||||
|
||||
The first method shows a query for all people with the given lastname. The query will be derived parsing the method name for constraints which can be concatenated with `And` and `Or`. Thus the method name will result in a query expression of`{"lastname" : lastname}`. The second example shows how pagination is applied to a query. Just equip your method signature with a `Pageable` parameter and let the method return a `Page` instance and we will automatically page the query accordingly. The third examples shows that you can query based on properties which are not a primitive type.
|
||||
|
||||
|
||||
NOTE: Note that for version 1.0 we currently don't support referring to parameters that are mapped as `DBRef` in the domain class.
|
||||
|
||||
@@ -154,6 +160,10 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete
|
||||
| Sample
|
||||
| Logical result
|
||||
|
||||
| `After`
|
||||
| `findByBirthdateAfter(Date date)`
|
||||
| `{"birthdate" : {"$gt" : date}}`
|
||||
|
||||
| `GreaterThan`
|
||||
| `findByAgeGreaterThan(int age)`
|
||||
| `{"age" : {"$gt" : age}}`
|
||||
@@ -162,6 +172,10 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete
|
||||
| `findByAgeGreaterThanEqual(int age)`
|
||||
| `{"age" : {"$gte" : age}}`
|
||||
|
||||
| `Before`
|
||||
| `findByBirthdateBefore(Date date)`
|
||||
| `{"birthdate" : {"$lt" : date}}`
|
||||
|
||||
| `LessThan`
|
||||
| `findByAgeLessThan(int age)`
|
||||
| `{"age" : {"$lt" : age}}`
|
||||
@@ -190,10 +204,18 @@ NOTE: Note that for version 1.0 we currently don't support referring to paramete
|
||||
| `findByFirstnameNull()`
|
||||
| `{"firstname" : null}`
|
||||
|
||||
| `Like`
|
||||
| `Like`, `StartingWith`, `EndingWith`
|
||||
| `findByFirstnameLike(String name)`
|
||||
| `{"firstname" : name} ( name as regex)`
|
||||
|
||||
| `Containing` on String
|
||||
| `findByFirstnameContaining(String name)`
|
||||
| `{"firstname" : name} (name as regex)`
|
||||
|
||||
| `Containing` on Collection
|
||||
| `findByAddressesContaining(Address address)`
|
||||
| `{"addresses" : { "$in" : address}}`
|
||||
|
||||
| `Regex`
|
||||
| `findByFirstnameRegex(String firstname)`
|
||||
| `{"firstname" : {"$regex" : firstname }}`
|
||||
|
||||
@@ -21,7 +21,7 @@ For most tasks you will find yourself using `MongoTemplate` or the Repository su
|
||||
[[mongodb-getting-started]]
|
||||
== Getting Started
|
||||
|
||||
Spring MongoDB support requires MongoDB 1.4 or higher and Java SE 5 or higher. The latest production release (2.4.9 as of this writing) is recommended. An easy way to bootstrap setting up a working environment is to create a Spring based project in http://spring.io/tools/sts[STS].
|
||||
Spring MongoDB support requires MongoDB 2.6 or higher and Java SE 6 or higher. An easy way to bootstrap setting up a working environment is to create a Spring based project in http://spring.io/tools/sts[STS].
|
||||
|
||||
First you need to set up a running Mongodb server. Refer to the http://docs.mongodb.org/manual/core/introduction/[Mongodb Quick Start guide] for an explanation on how to startup a MongoDB instance. Once installed starting MongoDB is typically a matter of executing the following command: `MONGO_HOME/bin/mongod`
|
||||
|
||||
@@ -38,7 +38,7 @@ Then add the following to pom.xml dependencies section.
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.4.1.RELEASE</version>
|
||||
<version>1.7.0.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@@ -48,7 +48,7 @@ Also change the version of Spring in the pom.xml to be
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<spring.framework.version>3.2.8.RELEASE</spring.framework.version>
|
||||
<spring.framework.version>4.0.9.RELEASE</spring.framework.version>
|
||||
----
|
||||
|
||||
You will also need to add the location of the Spring Milestone repository for maven to your pom.xml which is at the same level of your <dependencies/> element
|
||||
@@ -162,7 +162,7 @@ Even in this simple example, there are few things to take notice of
|
||||
[[mongo.examples-repo]]
|
||||
== Examples Repository
|
||||
|
||||
There is an https://github.com/spring-projects/spring-data-document-examples[github repository with several examples] that you can download and play around with to get a feel for how the library works.
|
||||
There is an https://github.com/spring-projects/spring-data-examples[github repository with several examples] that you can download and play around with to get a feel for how the library works.
|
||||
|
||||
[[mongodb-connectors]]
|
||||
== Connecting to MongoDB with Spring
|
||||
@@ -1156,6 +1156,96 @@ As you can see we use the `NearQuery` builder API to set up a query to return al
|
||||
|
||||
The geo near operations return a `GeoResults` wrapper object that encapsulates `GeoResult` instances. The wrapping `GeoResults` allows to access the average distance of all results. A single `GeoResult` object simply carries the entity found plus its distance from the origin.
|
||||
|
||||
[[mongo.geo-json]]
|
||||
=== GeoJSON Support
|
||||
|
||||
MongoDB supports http://geojeson.org/[GeoJSON] and simple (legacy) coordinate pairs for geospatial data. Those formats can both be used for storing as well as querying data.
|
||||
|
||||
NOTE: Please refer to the http://docs.mongodb.org/manual/core/2dsphere/#geospatial-indexes-store-geojson/[MongoDB manual on GeoJSON support] to learn about requirements and restrictions.
|
||||
|
||||
==== GeoJSON types in domain classes
|
||||
|
||||
Usage of http://geojeson.org/[GeoJSON] types in domain classes is straight forward. The `org.springframework.data.mongodb.core.geo` package contains types like `GeoJsonPoint`, `GeoJsonPolygon` and others. Those are extensions to the existing `org.springframework.data.geo` types.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public class Store {
|
||||
|
||||
String id;
|
||||
|
||||
/**
|
||||
* location is stored in GeoJSON format.
|
||||
* {
|
||||
* "type" : "Point",
|
||||
* "coordinates" : [ x, y ]
|
||||
* }
|
||||
*/
|
||||
GeoJsonPoint location;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== GeoJSON types in repository query methods
|
||||
|
||||
Using GeoJSON types as repository query parameters forces usage of the `$geometry` operator when creating the query.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public interface StoreRepository extends CrudRepository<Store, String> {
|
||||
|
||||
List<Store> findByLocationWithin(Polygon polygon); <1>
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* {
|
||||
* "location": {
|
||||
* "$geoWithin": {
|
||||
* "$geometry": {
|
||||
* "type": "Polygon",
|
||||
* "coordinates": [
|
||||
* [
|
||||
* [-73.992514,40.758934],
|
||||
* [-73.961138,40.760348],
|
||||
* [-73.991658,40.730006],
|
||||
* [-73.992514,40.758934]
|
||||
* ]
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
repo.findByLocationWithin( <2>
|
||||
new GeoJsonPolygon(
|
||||
new Point(-73.992514, 40.758934),
|
||||
new Point(-73.961138, 40.760348),
|
||||
new Point(-73.991658, 40.730006),
|
||||
new Point(-73.992514, 40.758934))); <3>
|
||||
|
||||
/*
|
||||
* {
|
||||
* "location" : {
|
||||
* "$geoWithin" : {
|
||||
* "$polygon" : [ [-73.992514,40.758934] , [-73.961138,40.760348] , [-73.991658,40.730006] ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
repo.findByLocationWithin( <4>
|
||||
new Polygon(
|
||||
new Point(-73.992514, 40.758934),
|
||||
new Point(-73.961138, 40.760348),
|
||||
new Point(-73.991658, 40.730006));
|
||||
----
|
||||
<1> Repository method definition using the commons type allows calling it with both GeoJSON and legacy format.
|
||||
<2> Use GeoJSON type the make use of `$geometry` operator.
|
||||
<3> Plase note that GeoJSON polygons need the define a closed ring.
|
||||
<4> Use legacy format `$polygon` operator.
|
||||
====
|
||||
|
||||
[[mongo.textsearch]]
|
||||
=== Full Text Queries
|
||||
|
||||
@@ -1340,17 +1430,21 @@ MongoDB allows to execute JavaScript functions on the server by either directly
|
||||
|
||||
=== Example Usage
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ScriptOperations scriptOps = template.scriptOps();
|
||||
|
||||
ServerSideJavaScript echoScript = new ExecutableMongoScript("function(x) { return x; }");
|
||||
scriptOps.execute(echoScript, "directly execute script");
|
||||
ExecutableMongoScript echoScript = new ExecutableMongoScript("function(x) { return x; }");
|
||||
scriptOps.execute(echoScript, "directly execute script"); <1>
|
||||
|
||||
scriptOps.register(new CallableMongoScript("echo", echoScript));
|
||||
scriptOps.call("echo", "execute script via name");
|
||||
scriptOps.register(new NamedMongoScript("echo", echoScript)); <2>
|
||||
scriptOps.call("echo", "execute script via name"); <3>
|
||||
----
|
||||
|
||||
<1> Execute the script directly without storing the function on server side.
|
||||
<2> Store the script using 'echo' as its name. The given name identifies the script and allows calling it later.
|
||||
<3> Execute the script with name 'echo' using the provided parameters.
|
||||
====
|
||||
|
||||
[[mongo.group]]
|
||||
== Group Operations
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 1.7.0.RELEASE (2015-03-23)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-1189 - Release 1.7 GA.
|
||||
* DATAMONGO-1181 - Add Jackson Module for GeoJSON types.
|
||||
* DATAMONGO-1180 - Incorrect exception message creation in PartTreeMongoQuery.
|
||||
* DATAMONGO-1179 - Update reference documentation.
|
||||
* DATAMONGO-1124 - Switch log level for cyclic reference index warnings from WARN to INFO.
|
||||
* DATAMONGO-979 - Add support for $size expression in project and group aggregation pipeline.
|
||||
|
||||
|
||||
Changes in version 1.7.0.RC1 (2015-03-05)
|
||||
-----------------------------------------
|
||||
* DATAMONGO-1173 - Release 1.7 RC1.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 1.7 RC1
|
||||
Spring Data MongoDB 1.7 GA
|
||||
Copyright (c) [2010-2015] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
Reference in New Issue
Block a user