Browse Source

DATAMONGO-326 - QueryMapper now delegates type conversion to MongoConverter.

QueryMapper now delegates to a MongoConverter instead of a plain ConversionService and invokes optional conversion on it. This optional conversion now removes type information from the created DBObject.
pull/1/head
Oliver Gierke 14 years ago
parent
commit
c7f7571f3f
  1. 15
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java
  2. 51
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  3. 11
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoTypeMapper.java
  4. 33
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/TypeKeyAware.java
  5. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoSimpleTypes.java
  6. 48
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java
  7. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceTests.java
  8. 24
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java
  9. 16
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

15
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryMapper.java

@ -25,6 +25,7 @@ import org.bson.types.ObjectId; @@ -25,6 +25,7 @@ import org.bson.types.ObjectId;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.util.Assert;
@ -40,15 +41,17 @@ import com.mongodb.DBObject; @@ -40,15 +41,17 @@ import com.mongodb.DBObject;
public class QueryMapper {
private final ConversionService conversionService;
private final MongoConverter converter;
/**
* Creates a new {@link QueryMapper} with the given {@link ConversionService}.
* Creates a new {@link QueryMapper} with the given {@link MongoConverter}.
*
* @param conversionService must not be {@literal null}.
* @param converter must not be {@literal null}.
*/
public QueryMapper(ConversionService conversionService) {
Assert.notNull(conversionService);
this.conversionService = conversionService;
public QueryMapper(MongoConverter converter) {
Assert.notNull(converter);
this.conversionService = converter.getConversionService();
this.converter = converter;
}
/**
@ -105,7 +108,7 @@ public class QueryMapper { @@ -105,7 +108,7 @@ public class QueryMapper {
value = convertId(value);
}
newDbo.put(newKey, value);
newDbo.put(newKey, converter.convertToMongoType(value));
}
return newDbo;

51
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -72,7 +72,7 @@ import com.mongodb.DBRef; @@ -72,7 +72,7 @@ import com.mongodb.DBRef;
* @author Oliver Gierke
* @author Jon Brisbin
*/
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware, TypeKeyAware {
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
@SuppressWarnings("rawtypes")
private static final TypeInformation<Map> MAP_TYPE_INFORMATION = ClassTypeInformation.from(Map.class);
@ -110,7 +110,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -110,7 +110,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
this.mongoDbFactory = mongoDbFactory;
this.mappingContext = mappingContext;
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext);
this.idMapper = new QueryMapper(conversionService);
this.idMapper = new QueryMapper(this);
}
/**
@ -126,14 +126,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -126,14 +126,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
mappingContext) : typeMapper;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.convert.TypeKeyAware#isTypeKey(java.lang.String)
*/
public boolean isTypeKey(String key) {
return typeMapper.isTypeKey(key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.convert.EntityConverter#getMappingContext()
@ -908,7 +900,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -908,7 +900,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
DBObject newDbo = new BasicDBObject();
this.write(obj, newDbo);
return newDbo;
return removeTypeInfoRecursively(newDbo);
}
public BasicDBList maybeConvertList(Iterable<?> source) {
@ -918,4 +910,41 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -918,4 +910,41 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
return newDbl;
}
/**
* Removes the type information from the conversion result.
*
* @param object
* @return
*/
private Object removeTypeInfoRecursively(Object object) {
if (!(object instanceof DBObject)) {
return object;
}
DBObject dbObject = (DBObject) object;
String keyToRemove = null;
for (String key : dbObject.keySet()) {
if (typeMapper.isTypeKey(key)) {
keyToRemove = key;
}
Object value = dbObject.get(key);
if (value instanceof BasicDBList) {
for (Object element : (BasicDBList) value) {
removeTypeInfoRecursively(element);
}
} else {
removeTypeInfoRecursively(value);
}
}
if (keyToRemove != null) {
dbObject.removeField(keyToRemove);
}
return dbObject;
}
}

11
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoTypeMapper.java

@ -20,11 +20,16 @@ import org.springframework.data.convert.TypeMapper; @@ -20,11 +20,16 @@ import org.springframework.data.convert.TypeMapper;
import com.mongodb.DBObject;
/**
* Combining interface to express Mongo specific {@link TypeMapper} implementations will be {@link TypeKeyAware} as
* well.
* Mongo-specific {@link TypeMapper} exposing that {@link DBObject}s might contain a type key.
*
* @author Oliver Gierke
*/
public interface MongoTypeMapper extends TypeMapper<DBObject>, TypeKeyAware {
public interface MongoTypeMapper extends TypeMapper<DBObject> {
/**
* Returns whether the given key is the type key.
*
* @return
*/
boolean isTypeKey(String key);
}

33
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/TypeKeyAware.java

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
/*
* 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.
* 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.convert.TypeMapper;
/**
* Interfaces for components being able to provide a {@link TypeMapper}.
*
* @author Oliver Gierke
*/
public interface TypeKeyAware {
/**
* Returns the {@link TypeMapper}.
*
* @return the {@link TypeMapper} or {@literal null} if none available.
*/
boolean isTypeKey(String key);
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoSimpleTypes.java

@ -19,6 +19,7 @@ import java.math.BigInteger; @@ -19,6 +19,7 @@ import java.math.BigInteger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
@ -48,6 +49,7 @@ public abstract class MongoSimpleTypes { @@ -48,6 +49,7 @@ public abstract class MongoSimpleTypes {
simpleTypes.add(ObjectId.class);
simpleTypes.add(CodeWScope.class);
simpleTypes.add(DBObject.class);
simpleTypes.add(Pattern.class);
MONGO_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
}

48
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java

@ -20,15 +20,11 @@ import java.util.Iterator; @@ -20,15 +20,11 @@ import java.util.Iterator;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.convert.MongoWriter;
import org.springframework.data.mongodb.core.convert.TypeKeyAware;
import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.util.Assert;
import com.mongodb.BasicDBList;
import com.mongodb.DBObject;
/**
* Custom {@link ParameterAccessor} that uses a {@link MongoWriter} to serialize parameters into Mongo format.
*
@ -111,49 +107,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor { @@ -111,49 +107,7 @@ public class ConvertingParameterAccessor implements MongoParameterAccessor {
* @return
*/
private Object getConvertedValue(Object value) {
if (!(writer instanceof TypeKeyAware)) {
return value;
}
return removeTypeInfoRecursively(writer.convertToMongoType(value), ((TypeKeyAware) writer));
}
/**
* Removes the type information from the conversion result.
*
* @param object
* @return
*/
private Object removeTypeInfoRecursively(Object object, TypeKeyAware typeKeyAware) {
if (!(object instanceof DBObject) || typeKeyAware == null) {
return object;
}
DBObject dbObject = (DBObject) object;
String keyToRemove = null;
for (String key : dbObject.keySet()) {
if (typeKeyAware.isTypeKey(key)) {
keyToRemove = key;
}
Object value = dbObject.get(key);
if (value instanceof BasicDBList) {
for (Object element : (BasicDBList) value) {
removeTypeInfoRecursively(element, typeKeyAware);
}
} else {
removeTypeInfoRecursively(value, typeKeyAware);
}
}
if (keyToRemove != null) {
dbObject.removeField(keyToRemove);
}
return dbObject;
return writer.convertToMongoType(value);
}
/**

1
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoNamespaceTests.java

@ -68,6 +68,7 @@ public class MongoNamespaceTests { @@ -68,6 +68,7 @@ public class MongoNamespaceTests {
}
@Test
@SuppressWarnings("deprecation")
public void testMongoSingletonWithPropertyPlaceHolders() throws Exception {
assertTrue(ctx.containsBean("mongo"));
MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&mongo");

24
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryMapperUnitTests.java

@ -17,6 +17,8 @@ package org.springframework.data.mongodb.core.query; @@ -17,6 +17,8 @@ package org.springframework.data.mongodb.core.query;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import java.math.BigInteger;
@ -59,7 +61,7 @@ public class QueryMapperUnitTests { @@ -59,7 +61,7 @@ public class QueryMapperUnitTests {
MappingMongoConverter converter = new MappingMongoConverter(factory, context);
converter.afterPropertiesSet();
mapper = new QueryMapper(converter.getConversionService());
mapper = new QueryMapper(converter);
}
@Test
@ -90,12 +92,12 @@ public class QueryMapperUnitTests { @@ -90,12 +92,12 @@ public class QueryMapperUnitTests {
}
/**
* @see DATADOC-278
* @see DATAMONGO-278
*/
@Test
public void translates$NeCorrectly() {
Criteria criteria = Criteria.where("foo").ne(new ObjectId().toString());
Criteria criteria = where("foo").ne(new ObjectId().toString());
DBObject result = mapper.getMappedObject(criteria.getCriteriaObject(), context.getPersistentEntity(Sample.class));
Object object = result.get("_id");
@ -104,6 +106,18 @@ public class QueryMapperUnitTests { @@ -104,6 +106,18 @@ public class QueryMapperUnitTests {
assertThat(dbObject.get("$ne"), is(ObjectId.class));
}
/**
* @see DATAMONGO-326
*/
@Test
public void handlesEnumsCorrectly() {
Query query = query(where("foo").is(Enum.INSTANCE));
DBObject result = mapper.getMappedObject(query.getQueryObject(), null);
Object object = result.get("foo");
assertThat(object, is(String.class));
}
class Sample {
@Id
@ -115,4 +129,8 @@ public class QueryMapperUnitTests { @@ -115,4 +129,8 @@ public class QueryMapperUnitTests {
@Id
private BigInteger id;
}
enum Enum {
INSTANCE;
}
}

16
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java

@ -30,7 +30,6 @@ import org.junit.Before; @@ -30,7 +30,6 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
@ -50,9 +49,6 @@ import org.springframework.data.repository.Repository; @@ -50,9 +49,6 @@ import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.parser.PartTree;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Unit test for {@link MongoQueryCreator}.
*
@ -72,14 +68,12 @@ public class MongoQueryCreatorUnitTests { @@ -72,14 +68,12 @@ public class MongoQueryCreatorUnitTests {
public void setUp() throws SecurityException, NoSuchMethodException {
context = new MongoMappingContext();
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Throwable {
DBObject dbObject = (DBObject) invocation.getArguments()[1];
dbObject.put("value", new BasicDBObject("value", "value"));
return null;
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArguments()[0];
}
}).when(converter).write(any(), Mockito.any(DBObject.class));
}).when(converter).convertToMongoType(any());
}
@Test

Loading…
Cancel
Save